Skip to content

Commit

Permalink
code coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
guillaume-pujol committed Jan 19, 2024
1 parent 28737c3 commit eb8d2d8
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 32 deletions.
55 changes: 28 additions & 27 deletions binapy/binapy.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import re
import secrets
from contextlib import suppress
from functools import wraps
from typing import (
Any,
Expand Down Expand Up @@ -117,13 +118,13 @@ def re_match(self, pattern: str, encoding: str = "ascii") -> str:
the decoded, matching `str`
Raises:
ValueError: if the decoded str doesn't match `pattern`
ValueError: if the decoded str does not match `pattern`
"""
res = self.decode(encoding)
if re.match(pattern, res):
return res
msg = f"This value doesn't match pattern {pattern}"
msg = f"This value does not match pattern {pattern}"
raise ValueError(msg)

def text(self, encoding: str = "ascii") -> str:
Expand Down Expand Up @@ -354,7 +355,7 @@ def _get_checker(cls, extension_name: str) -> Callable[..., bool]:
extension_methods = cls._get_extension_methods(extension_name)
method = extension_methods.get("check")
if method is None:
msg = f"Extension {extension_name} doesn't have a checker method"
msg = f"Extension '{extension_name}' does not have a checker method"
raise NotImplementedError(msg)
return method

Expand All @@ -363,7 +364,7 @@ def _get_decoder(cls, extension_name: str) -> Callable[..., BinaPy]:
extension_methods = cls._get_extension_methods(extension_name)
method = extension_methods.get("decode")
if method is None:
msg = f"Extension {extension_name} doesn't have a decode method"
msg = f"Extension '{extension_name}' does not have a decode method"
raise NotImplementedError(msg)
return method

Expand All @@ -372,7 +373,7 @@ def _get_encoder(cls, extension_name: str) -> Callable[..., BinaPy]:
extension_methods = cls._get_extension_methods(extension_name)
method = extension_methods.get("encode")
if method is None:
msg = f"Extension {extension_name} doesn't have an encode method"
msg = f"Extension '{extension_name}' does not have an encode method"
raise NotImplementedError(msg)
return method

Expand All @@ -381,7 +382,7 @@ def _get_parser(cls, extension_name: str) -> Callable[..., Any]:
extension_methods = cls._get_extension_methods(extension_name)
method = extension_methods.get("parse")
if method is None:
msg = f"Extension {extension_name} doesn't have a parse method"
msg = f"Extension '{extension_name}' does not have a parse method"
raise NotImplementedError(msg)
return method

Expand All @@ -390,7 +391,7 @@ def _get_serializer(cls, extension_name: str) -> Callable[..., BinaPy]:
extension_methods = cls._get_extension_methods(extension_name)
method = extension_methods.get("serialize")
if method is None:
msg = f"Extension {extension_name} doesn't have a serialize method"
msg = f"Extension '{extension_name}' does not have a serialize method"
raise NotImplementedError(msg)
return method

Expand Down Expand Up @@ -440,12 +441,12 @@ def decode_from(self, name: str, *args: Any, **kwargs: Any) -> BinaPy:

return decoder(self, *args, **kwargs)

def check(self, name: str, *, decode: bool = False, raise_on_error: bool = False) -> bool: # noqa: PLR0912
def check(self, name: str, *, decode: bool = False, raise_on_error: bool = False) -> bool:
"""Check that this BinaPy conforms to a given format extension.
Args:
name: the name of the extension to check
decode: if `True`, and the given extension doesn't have a checker method,
decode: if `True`, and the given extension does not have a checker method,
try to decode this BinaPy using the decoder method to check if that works.
raise_on_error: if `True`, exceptions from the checker method, if any,
will be raised instead of returning `False`.
Expand All @@ -454,7 +455,7 @@ def check(self, name: str, *, decode: bool = False, raise_on_error: bool = False
a boolean, that is True if this BinaPy conforms to the given extension format, False otherwise.
"""
# raises an exception in case the extension doesn't exist
# raises an exception in case the extension does not exist
self._get_extension_methods(name)

try:
Expand All @@ -468,20 +469,19 @@ def check(self, name: str, *, decode: bool = False, raise_on_error: bool = False
raise exc from exc
return False
except NotImplementedError:
try:
# if checker is not implemented and decode is True, try to decode instead
if decode:
decoder = self._get_decoder(name)
try:
decoder(self)
except Exception as exc:
if raise_on_error:
raise exc from exc
return False
else:
return True
except NotImplementedError:
return False
# if checker is not implemented and decode is True, try to decode instead
if decode:
decoder = self._get_decoder(name)
try:
decoder(self)
except Exception as exc:
if raise_on_error:
raise exc from exc
return False
else:
return True
else:
raise
return False

def check_all(self, *, decode: bool = False) -> list[str]:
Expand All @@ -498,9 +498,10 @@ def check_all(self, *, decode: bool = False) -> list[str]:

def get_results() -> Iterator[str]:
for name in self.extensions:
success = self.check(name, decode=decode)
if success is True:
yield name
with suppress(NotImplementedError):
success = self.check(name, decode=decode)
if success is True:
yield name

return list(get_results())

Expand Down
30 changes: 28 additions & 2 deletions tests/test_binapy.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,30 @@ def test_unknown_features() -> None:
with pytest.raises(NotImplementedError):
BinaPy.serialize_to("something_not_known", {"foo": "bar"})

@binapy_encoder("something_known")
def encode_something(bp: bytes) -> bytes:
return bp

with pytest.raises(NotImplementedError, match="Extension 'something_known' does not have a decode method"):
bp.decode_from("something_known")

with pytest.raises(NotImplementedError, match="Extension 'something_known' does not have a parse method"):
bp.parse_from("something_known")

with pytest.raises(NotImplementedError, match="Extension 'something_known' does not have a serialize method"):
bp.serialize_to("something_known")

with pytest.raises(NotImplementedError, match="Extension 'something_known' does not have a checker method"):
bp.check("something_known")

@binapy_decoder("something_else")
def decode_something_else(bp: bytes) -> bytes:
return bp

with pytest.raises(NotImplementedError, match="Extension 'something_else' does not have an encode method"):
bp.encode_to("something_else")



def test_exceptions() -> None:
@binapy_decoder("some_feature")
Expand All @@ -128,15 +152,17 @@ def decode_some_feature(bp: BinaPy) -> BinaPy:

bp = BinaPy()

assert bp.check("some_feature") is False
with pytest.raises(NotImplementedError):
bp.check("some_feature")
assert bp.check("some_feature", decode=True) is True

@binapy_decoder("other_feature")
def check_other_feature(bp: BinaPy) -> bool:
raise ValueError()

bp = BinaPy()
assert bp.check("other_feature") is False
with pytest.raises(NotImplementedError):
bp.check("other_feature")
assert bp.check("other_feature", decode=True) is False

with pytest.raises(ValueError):
Expand Down
18 changes: 15 additions & 3 deletions tests/test_json.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import uuid
from collections import UserDict
from datetime import datetime, timedelta, timezone
from typing import Iterable

from binapy import BinaPy

Expand All @@ -14,6 +16,12 @@ def test_json() -> None:
def test_json_encoder() -> None:
"""Datetimes are serialized to integer epoch timestamps, but integer stay integers when
parsed."""

user_dict = UserDict({"my": "dict"})
def iterable() -> Iterable[int]:
for i in range(5):
yield i

bp = BinaPy.serialize_to(
"json",
{
Expand All @@ -26,15 +34,19 @@ def test_json_encoder() -> None:
second=40,
tzinfo=timezone(timedelta(seconds=0)),
),
"foo": uuid.UUID("71509952-ec4f-4854-84e7-fa452994b51d"),
"uuid": uuid.UUID("71509952-ec4f-4854-84e7-fa452994b51d"),
"user_dict": user_dict,
"iterable": iterable()
},
sort_keys=True,
)
assert bp == b'{"foo":"71509952-ec4f-4854-84e7-fa452994b51d","iat":1600000000}'
assert bp == b'{"iat":1600000000,"iterable":[0,1,2,3,4],"user_dict":{"my":"dict"},"uuid":"71509952-ec4f-4854-84e7-fa452994b51d"}'

assert bp.parse_from("json") == {
"iat": 1600000000,
"foo": "71509952-ec4f-4854-84e7-fa452994b51d",
"iterable": [0, 1, 2, 3, 4],
"uuid": "71509952-ec4f-4854-84e7-fa452994b51d",
"user_dict": {"my": "dict"}
}


Expand Down

0 comments on commit eb8d2d8

Please sign in to comment.