Repository: xconnio/wampproto-python (language: python)

Issue:
Json Serializer
Need json serializer for serializing and deserializing wamp messages


Discussion / hints:

Fix patch:
diff --git a/wamp/serializers/__init__.py b/wamp/serializers/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/wamp/serializers/json.py b/wamp/serializers/json.py
new file mode 100644
index 0000000..ecafd06
--- /dev/null
+++ b/wamp/serializers/json.py
@@ -0,0 +1,16 @@
+import json
+
+from wamp.messages.message import Message
+from wamp.serializers.serializer import to_message
+from wamp.serializers.serializer import Serializer
+
+
+class JSONSerializer(Serializer):
+    def serialize(self, message: Message) -> bytes:
+        json_str = json.dumps(message.marshal())
+        return json_str.encode("utf-8")
+
+    def deserialize(self, data: bytes) -> Message:
+        json_str = data.decode("utf-8")
+        wamp_message = json.loads(json_str)
+        return to_message(wamp_message)
diff --git a/wamp/serializers/serializer.py b/wamp/serializers/serializer.py
new file mode 100644
index 0000000..20673c4
--- /dev/null
+++ b/wamp/serializers/serializer.py
@@ -0,0 +1,40 @@
+from wamp.messages.hello import Hello
+from wamp.messages.abort import Abort
+from wamp.messages.welcome import Welcome
+from wamp.messages.goodbye import Goodbye
+from wamp.messages.message import Message
+from wamp.messages.challenge import Challenge
+from wamp.messages.authenticate import Authenticate
+
+
+class Serializer:
+    def serialize(self, message: Message) -> bytes:
+        raise NotImplementedError()
+
+    def deserialize(self, message: Message) -> Message:
+        raise NotImplementedError()
+
+
+def to_message(message: list) -> Message:
+    if not isinstance(message, list):
+        raise TypeError(f"invalid type '{type(message)}', expected a list")
+
+    message_type = message[0]
+    if not isinstance(message_type, int):
+        raise TypeError(f"invalid message type '{type(message[0])}', expected an integer")
+
+    match message_type:
+        case Hello.MESSAGE_TYPE:
+            return Hello.parse(message)
+        case Welcome.MESSAGE_TYPE:
+            return Welcome.parse(message)
+        case Abort.MESSAGE_TYPE:
+            return Abort.parse(message)
+        case Challenge.MESSAGE_TYPE:
+            return Challenge.parse(message)
+        case Authenticate.MESSAGE_TYPE:
+            return Authenticate.parse(message)
+        case Goodbye.MESSAGE_TYPE:
+            return Goodbye.parse(message)
+        case _:
+            raise ValueError("unknown message type")


Test patch:
diff --git a/tests/serializers/__init__.py b/tests/serializers/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/serializers/json.py b/tests/serializers/json.py
new file mode 100644
index 0000000..9fa9af1
--- /dev/null
+++ b/tests/serializers/json.py
@@ -0,0 +1,15 @@
+from wamp.messages.hello import Hello
+from wamp.serializers.json import JSONSerializer
+
+
+def test_serializer():
+    serializer = JSONSerializer()
+    hello = Hello.parse([1, "realm1", {"roles": {"callee": {}}}])
+
+    data = serializer.serialize(hello)
+    assert isinstance(data, bytes)
+
+    obj = serializer.deserialize(data)
+    assert isinstance(obj, Hello)
+    assert obj.realm == hello.realm
+    assert obj.roles == hello.roles
diff --git a/tests/serializers/serializer.py b/tests/serializers/serializer.py
new file mode 100644
index 0000000..663286a
--- /dev/null
+++ b/tests/serializers/serializer.py
@@ -0,0 +1,74 @@
+import pytest
+
+from wamp.serializers.serializer import to_message
+
+
+def test_to_message_with_invalid_type():
+    message = "Hello World!"
+    with pytest.raises(TypeError) as exc_info:
+        to_message(message)
+
+    assert str(exc_info.value) == f"invalid type '{type(message)}', expected a list"
+
+
+def test_to_message_with_invalid_message_type():
+    message = ["hi"]
+    with pytest.raises(TypeError) as exc_info:
+        to_message(message)
+
+    assert str(exc_info.value) == f"invalid message type '{type(message[0])}', expected an integer"
+
+
+def test_to_message_with_invalid_case():
+    with pytest.raises(ValueError) as exc_info:
+        to_message([999])
+
+    assert str(exc_info.value) == "unknown message type"
+
+
+def test_to_message_with_hello():
+    realm = "realm1"
+    details = {"roles": {"callee": {}}}
+    hello = to_message([1, realm, details])
+    assert hello.realm == realm
+    assert hello.roles == details["roles"]
+
+
+def test_to_message_with_welcome():
+    session_id = 231
+    details = {"roles": {"callee": {}}}
+    welcome = to_message([2, session_id, details])
+    assert welcome.session_id == session_id
+    assert welcome.roles == details["roles"]
+
+
+def test_to_message_with_abort():
+    details = {"message": "The realm does not exist."}
+    reason = "wamp.error.no_such_realm"
+    abort = to_message([3, details, reason])
+    assert abort.details == details
+    assert abort.reason == reason
+
+
+def test_to_message_with_challenge():
+    authmethod = "cryptosign"
+    extra = {"channel_binding": "tls-unique"}
+    challenge = to_message([4, authmethod, extra])
+    assert challenge.authmethod == authmethod
+    assert challenge.extra == extra
+
+
+def test_to_message_with_authenticate():
+    signature = "signature"
+    extra = {"channel_binding": "null"}
+    authenticate = to_message([5, signature, extra])
+    assert authenticate.signature == signature
+    assert authenticate.extra == extra
+
+
+def test_to_message_with_goodbye():
+    details = {"message": "The host is shutting down now."}
+    reason = "wamp.close.system_shutdown"
+    goodbye = to_message([6, details, reason])
+    assert goodbye.details == details
+    assert goodbye.reason == reason