Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@
([#10](https://github.com/davep/gophermap/pull/10))
- Added an optional strict mode (and, in doing so, added an exception back).
([#12](https://github.com/davep/gophermap/pull/12))
- Added `has_error` instance property to the `GopherMap` class.
([#13](https://github.com/davep/gophermap/pull/13))
- Added `is_likely_a_map` as a class method.
([#13](https://github.com/davep/gophermap/pull/13))
- Added `is_likely_error` as a class method.
([#13](https://github.com/davep/gophermap/pull/13))

## v0.2.0

Expand Down
51 changes: 50 additions & 1 deletion src/gophermap/gopher_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@

##############################################################################
# Local imports.
from .exceptions import EmptyMap
from .exceptions import EmptyMap, GopherMapError
from .item import GopherItem
from .item_type import ItemType

##############################################################################
EOF: Final[str] = "."
Expand Down Expand Up @@ -64,5 +65,53 @@ def items(self) -> tuple[GopherItem, ...]:
"""
return tuple(self._parse_map(self._raw))

@cached_property
def has_error(self) -> bool:
"""Whether the Gopher map contains an error item.

Raises:
EmptyMap: If the map is empty and strict mode is enabled.
NoFields: If the line is missing a tab character and strict mode is enabled.
UnknownItemType: If the item type is unknown and strict mode is enabled.

Note:
The mentioned exceptions will be raised on accessing this
property, if in strict mode. If you wish to check for errors
without raising exceptions, use the [`is_likely_error` class
method][gophermap.GopherMap.is_likely_error], to test instead.
"""
return any(item.type is ItemType.ERROR for item in self.items)

@classmethod
def is_likely_a_map(cls, text: str) -> bool:
"""Determine if the text is likely a valid Gopher map.

Args:
text: The text of the Gopher map.

Returns:
True if the text is likely a valid Gopher map, False otherwise.
"""
try:
_ = cls(text, strict=True).items
except GopherMapError:
return False
return True

@classmethod
def is_likely_error(cls, text: str) -> bool:
"""Determine if the text is likely a Gopher error message.

Args:
text: The text to test.

Returns:
True if the text is likely a Gopher error message, False otherwise.
"""
try:
return cls(text, strict=True).has_error
except GopherMapError:
return False


### gopher_map.py ends here
54 changes: 54 additions & 0 deletions tests/test_gopher_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,58 @@ def test_strict_on_bad_map(test_map: str) -> None:
_ = GopherMap(test_map, strict=True).items


##############################################################################
@mark.parametrize(
"test_map, expected",
[
("iHello\tworld\tlocalhost\t70\r\n3Error\tworld\tlocalhost\t70\r\n.\r\n", True),
("iHello\tworld\tlocalhost\t70\r\n.\r\n", False),
("3Error\tworld\tlocalhost\t70\r\n.\r\n", True),
("This is just some random test", False),
(".\r\n", False),
("", False),
],
)
def test_has_error(test_map: str, expected: bool) -> None:
"""Test that has_error returns True if the map contains an error item."""
assert GopherMap(test_map).has_error is expected


##############################################################################
@mark.parametrize(
"test_map, expected",
[
("", False),
("iHello\tworld\tlocalhost\t70\r\n3Error\tworld\tlocalhost\t70\r\n.\r\n", True),
("iHello\tworld\tlocalhost\t70\r\n.\r\n", True),
("3Error\tworld\tlocalhost\t70\r\n.\r\n", True),
("This is just some random test", False),
("Hello\tworld\tlocalhost\t70\r\n.\r\n", False),
("hello\tworld\tlocalhost\t70\r\n.\r\n", True),
(".\r\n", True),
],
)
def test_is_likel_a_map(test_map: str, expected: bool) -> None:
"""Test is_likely_a_map returns True if the map is likely a valid Gopher map."""
assert GopherMap.is_likely_a_map(test_map) is expected


##############################################################################
@mark.parametrize(
"test_map, expected",
[
("iHello\tworld\tlocalhost\t70\r\n3Error\tworld\tlocalhost\t70\r\n.\r\n", True),
("iHello\tworld\tlocalhost\t70\r\n.\r\n", False),
("3Error\tworld\tlocalhost\t70\r\n.\r\n", True),
("This is just some random test", False),
("3. This is just some random test\r\n.\r\n", False),
(".\r\n", False),
("", False),
],
)
def test_is_likely_error(test_map: str, expected: bool) -> None:
"""Test that is_likely_error returns True if the map contains an error item."""
assert GopherMap.is_likely_error(test_map) is expected


### test_gopher_map.py ends here
Loading