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
7 changes: 7 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"python.testing.pytestArgs": [
"tests"
],
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true
}
23 changes: 22 additions & 1 deletion android_sms_gateway/domain.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import dataclasses
import typing as t

from .enums import ProcessState, WebhookEvent
from .enums import ProcessState, WebhookEvent, MessagePriority


def snake_to_camel(snake_str):
Expand All @@ -11,6 +11,20 @@ def snake_to_camel(snake_str):

@dataclasses.dataclass(frozen=True)
class Message:
"""
Represents an SMS message.

Attributes:
message (str): The message text.
phone_numbers (List[str]): A list of phone numbers to send the message to.
with_delivery_report (bool): Whether to request a delivery report. Defaults to True.
is_encrypted (bool): Whether the message is encrypted. Defaults to False.
id (Optional[str]): The message ID. Defaults to None.
ttl (Optional[int]): The time-to-live in seconds. Defaults to None.
sim_number (Optional[int]): The SIM number to use. Defaults to None.
priority (Optional[MessagePriority]): The priority of the message. Defaults to None.
"""

message: str
phone_numbers: t.List[str]
with_delivery_report: bool = True
Expand All @@ -19,8 +33,15 @@ class Message:
id: t.Optional[str] = None
ttl: t.Optional[int] = None
sim_number: t.Optional[int] = None
priority: t.Optional[MessagePriority] = None

def asdict(self) -> t.Dict[str, t.Any]:
"""
Returns a dictionary representation of the message.

Returns:
Dict[str, Any]: A dictionary representation of the message.
"""
return {
snake_to_camel(field.name): getattr(self, field.name)
for field in dataclasses.fields(self)
Expand Down
16 changes: 16 additions & 0 deletions android_sms_gateway/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,19 @@ class WebhookEvent(enum.Enum):

SYSTEM_PING = "system:ping"
"""Triggered when the device pings the server."""


class MessagePriority(enum.IntEnum):
"""Priority levels for messages."""

MINIMUM = -128
"""Minimum priority level."""

DEFAULT = 0
"""Default priority level."""

BYPASS_THRESHOLD = 100
"""Priority level to bypass limits and delays."""

MAXIMUM = 127
"""Maximum priority level."""
128 changes: 126 additions & 2 deletions tests/test_domain.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import pytest

from android_sms_gateway.enums import WebhookEvent
from android_sms_gateway.domain import MessageState, RecipientState, Webhook
from android_sms_gateway.enums import WebhookEvent, MessagePriority
from android_sms_gateway.domain import MessageState, RecipientState, Webhook, Message


# Test for successful instantiation from a dictionary
Expand Down Expand Up @@ -135,3 +135,127 @@ def test_webhook_asdict():
}

assert webhook.asdict() == expected_dict


@pytest.mark.parametrize(
"message_content,phone_numbers,with_delivery_report,is_encrypted,id,ttl,sim_number,priority,expected",
[
(
"Hello, world!",
["123", "456"],
True,
False,
"msg_123",
300,
1,
MessagePriority.BYPASS_THRESHOLD,
{
"message": "Hello, world!",
"phoneNumbers": ["123", "456"],
"withDeliveryReport": True,
"isEncrypted": False,
"id": "msg_123",
"ttl": 300,
"simNumber": 1,
"priority": 100,
},
),
(
"Hello, world!",
["123", "456"],
True,
False,
None,
None,
None,
None,
{
"message": "Hello, world!",
"phoneNumbers": ["123", "456"],
"withDeliveryReport": True,
"isEncrypted": False,
},
),
(
"Hello, world!",
["123", "456"],
True,
False,
"msg_123",
None,
1,
None,
{
"message": "Hello, world!",
"phoneNumbers": ["123", "456"],
"withDeliveryReport": True,
"isEncrypted": False,
"id": "msg_123",
"simNumber": 1,
},
),
(
"Hello, world!",
["123", "456"],
True,
False,
"msg_123",
None,
None,
MessagePriority.DEFAULT,
{
"message": "Hello, world!",
"phoneNumbers": ["123", "456"],
"withDeliveryReport": True,
"isEncrypted": False,
"id": "msg_123",
"priority": 0,
},
),
(
"Hi",
["555"],
True,
False,
None,
None,
None,
MessagePriority.MINIMUM,
{
"message": "Hi",
"phoneNumbers": ["555"],
"withDeliveryReport": True,
"isEncrypted": False,
"priority": -128,
},
),
],
)
def test_message_asdict(
message_content,
phone_numbers,
with_delivery_report,
is_encrypted,
id,
ttl,
sim_number,
priority,
expected,
):
"""
Tests that a Message instance can be successfully converted to a dictionary
representation with camelCase keys and that only non-None fields are included.
Uses parametrized testing to cover multiple scenarios.
"""
message = Message(
message=message_content,
phone_numbers=phone_numbers,
with_delivery_report=with_delivery_report,
is_encrypted=is_encrypted,
id=id,
ttl=ttl,
sim_number=sim_number,
priority=priority,
)

assert message.asdict() == expected