Skip to content

Commit

Permalink
feat: add has_key conjecture
Browse files Browse the repository at this point in the history
  • Loading branch information
danielknell authored Jun 22, 2022
1 parent 2122347 commit 44f5741
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 1 deletion.
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,17 @@ Matching anything.
>>> assert "abc" == conjecture.anything()
```

#### Mapping

Matching keys.

```pycon
>>> import conjecture
>>> assert {"a": 1} == conjecture.has_key("a")
>>> assert {"a": 1} == conjecture.has_key("a", of=1)
>>> assert {"a": 1} == conjecture.has_key("a", of=conjecture.less_than(5))
```

#### Object

Matching instances of a class.
Expand Down
2 changes: 2 additions & 0 deletions src/conjecture/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

from conjecture.base import AllOfConjecture, AnyOfConjecture, Conjecture
from conjecture.general import all_of, any_of, anything, has, none
from conjecture.mapping import has_key
from conjecture.object import equal_to, has_attribute, instance_of
from conjecture.rich import (
greater_than,
Expand All @@ -29,6 +30,7 @@
"greater_than",
"has",
"has_attribute",
"has_key",
"instance_of",
"length_of",
"less_than_or_equal_to",
Expand Down
35 changes: 35 additions & 0 deletions src/conjecture/mapping.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"""mapping conjectures."""

import collections.abc

import conjecture.base

sentinel = object()


def has_key(value: str, of: object = sentinel) -> conjecture.base.Conjecture:
"""
Has attribute.
Propose that the value has the given key
>>> assert value == conjecture.has_key("foo")
>>> assert value == conjecture.has_key("foo", of=5)
>>> assert value == conjecture.has_key("foo", of=conjecture.less_than(10))
:param value: the name of the key
:param of: an optional value or conjecture to compare the key value against
:return: a conjecture object
"""
# pylint: disable=invalid-name
# of is a perfectly valid name.

if of is sentinel:
return conjecture.base.Conjecture(
lambda x: isinstance(x, collections.abc.Mapping) and value in x
)

return conjecture.base.Conjecture(
lambda x: isinstance(x, collections.abc.Mapping) and x.get(value) == of
)
2 changes: 1 addition & 1 deletion src/conjecture/object.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def has_attribute(value: str, of: object = sentinel) -> conjecture.base.Conjectu
# pylint: disable=invalid-name
# of is a perfectly valid name.

if of == sentinel:
if of is sentinel:
return conjecture.base.Conjecture(lambda x: hasattr(x, value))

return conjecture.base.Conjecture(lambda x: getattr(x, value, sentinel) == of)
108 changes: 108 additions & 0 deletions tests/unit/test_has_key.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
"""
Tests for :meth:`conjecture.has_key`.
"""

import string

import hypothesis
import hypothesis.strategies as st

import conjecture


@hypothesis.given(
value=st.text(alphabet=string.ascii_letters, min_size=1),
other=st.integers(),
)
def test_should_match_when_key_exists(value: str, other: int) -> None:
"""
has_key() should match when key exists.
"""
mapping = {value: other}

assert conjecture.has_key(value).resolve(mapping)


@hypothesis.given(
value=st.text(alphabet=string.ascii_letters, min_size=1),
key=st.text(alphabet=string.ascii_letters, min_size=1),
other=st.integers(),
)
def test_should_not_match_when_key_doesnt_exists(
value: str,
key: str,
other: int,
) -> None:
"""
has_key() should not match when key doesn't exist.
"""
hypothesis.assume(value != key)

mapping = {key: other}

assert not conjecture.has_key(value).resolve(mapping)


@hypothesis.given(
value=st.text(alphabet=string.ascii_letters, min_size=1),
other=st.integers(),
)
def test_should_match_when_key_value_matches(value: str, other: int) -> None:
"""
has_key() should match when key value matches.
"""
mapping = {value: other}

assert conjecture.has_key(value, of=other).resolve(mapping)


@hypothesis.given(
value=st.text(alphabet=string.ascii_letters, min_size=1),
wrong=st.integers(),
other=st.integers(),
)
def test_should_not_match_when_key_value_doesnt_match(
value: str,
wrong: int,
other: int,
) -> None:
"""
has_key() should not match when key value doesn't match.
"""
hypothesis.assume(wrong != other)

mapping = {value: wrong}

assert not conjecture.has_key(value, of=other).resolve(mapping)


@hypothesis.given(
value=st.text(alphabet=string.ascii_letters, min_size=1),
other=st.integers(),
)
def test_should_match_when_key_value_matches_conjecture(value: str, other: int) -> None:
"""
has_key() should match when key value matches conjecture.
"""
mapping = {value: other}

always = conjecture.has(lambda x: True)

assert conjecture.has_key(value, of=always).resolve(mapping)


@hypothesis.given(
value=st.text(alphabet=string.ascii_letters, min_size=1),
other=st.integers(),
)
def test_should_not_match_when_key_value_doesnt_match_conjecture(
value: str, other: int
) -> None:
"""
has_key() should not match when key value doesn't match conjecture.
"""
mapping = {value: other}

never = conjecture.has(lambda x: False)

assert not conjecture.has_key(value, of=never).resolve(mapping)

0 comments on commit 44f5741

Please sign in to comment.