Skip to content

Commit

Permalink
Recursively convert Typevalue to JSON
Browse files Browse the repository at this point in the history
Closes #870
  • Loading branch information
Alexander Senier authored and senier committed Dec 8, 2021
1 parent f94b853 commit 2dc796b
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 12 deletions.
32 changes: 32 additions & 0 deletions rflx/pyrflx/typevalue.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,10 @@ def value(self) -> ValueType:
def accepted_type(self) -> type:
raise NotImplementedError

@abstractmethod
def as_json(self) -> object:
raise NotImplementedError

def clone(self) -> "TypeValue":
return self.__class__(self._type)

Expand Down Expand Up @@ -217,6 +221,9 @@ def bitstring(self) -> Bitstring:
def accepted_type(self) -> type:
return int

def as_json(self) -> object:
return self._value


class EnumValue(ScalarValue):

Expand Down Expand Up @@ -316,6 +323,9 @@ def accepted_type(self) -> type:
def literals(self) -> ty.Mapping[Name, Expr]:
return self.__literals

def as_json(self) -> object:
return (self._value[0], self._value[1].value)


class CompositeValue(TypeValue):
def __init__(self, vtype: Composite) -> None:
Expand Down Expand Up @@ -416,6 +426,9 @@ def bitstring(self) -> Bitstring:
def accepted_type(self) -> type:
return bytes

def as_json(self) -> ty.Optional[bytes]:
return self._value


class SequenceValue(CompositeValue):

Expand Down Expand Up @@ -526,6 +539,9 @@ def accepted_type(self) -> type:
def element_type(self) -> Type:
return self._element_type

def as_json(self) -> object:
return [f.as_json() for f in self._value]


class MessageValue(TypeValue):
# pylint: disable=too-many-instance-attributes
Expand Down Expand Up @@ -683,6 +699,22 @@ def inner_messages(self) -> ty.List["MessageValue"]:
messages.append(typeval.nested_message)
return messages

def as_json(self) -> ty.Dict[str, object]:
result: ty.Dict[str, object] = {}
for field_name in self.valid_fields:
field_value = self.get(field_name)
if isinstance(field_value, MessageValue):
result[field_name] = field_value.bytestring.hex()
elif isinstance(field_value, bytes):
result[field_name] = field_value.hex()
elif isinstance(field_value, (int, str)):
result[field_name] = field_value
elif isinstance(field_value, list):
result[field_name] = [f.as_json() for f in field_value]
else:
raise NotImplementedError(f"Unsupported: {type(field_value)}")
return result

def _valid_refinement_condition(self, refinement: "RefinementValue") -> bool:
return self.__simplified(refinement.condition) == TRUE

Expand Down
13 changes: 1 addition & 12 deletions rflx/validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -391,17 +391,6 @@ class ValidationResult:
valid_original_message: bool
valid_parser_result: bool

def __get_field_values(self) -> Dict[str, object]:
parsed_field_values: Dict[str, object] = {}
for field_name in self.parsed_message.valid_fields:
field_value = self.parsed_message.get(field_name)
if isinstance(field_value, MessageValue):
field_value = field_value.bytestring.hex()
if isinstance(field_value, bytes):
field_value = field_value.hex()
parsed_field_values[field_name] = field_value
return parsed_field_values

def as_json(self) -> Dict[str, object]:
output = {
"file name": str(self.message_path),
Expand All @@ -411,7 +400,7 @@ def as_json(self) -> Dict[str, object]:
}
if self.parsed_message.valid_message:
output["parsed"] = self.parsed_message.bytestring.hex()
output["parsed field values"] = self.__get_field_values()
output["parsed field values"] = self.parsed_message.as_json()
if self.parser_error is not None:
output["error"] = self.parser_error

Expand Down
25 changes: 25 additions & 0 deletions tests/integration/pyrflx_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -352,3 +352,28 @@ def test_no_verification_icmp_checksum(
assert icmp_checksum_unv.valid_message
assert icmp_checksum_unv.get("Checksum") == icmp_checksum_message_value.get("Checksum")
assert icmp_checksum_unv.bytestring == icmp_checksum_message_value.bytestring


def test_sequence_message_serialization(
sequence_message_package: Package, message_sequence_value: MessageValue
) -> None:
sequence_message_one = sequence_message_package.new_message("Sequence_Element")
sequence_message_one.set("Byte", 5)
sequence_message_two = sequence_message_package.new_message("Sequence_Element")
sequence_message_two.set("Byte", 6)
sequence: List[TypeValue] = [sequence_message_one, sequence_message_two]
message_sequence_value.set("Length", 2)
message_sequence_value.set("Sequence_Field", sequence)
assert message_sequence_value.valid_message
assert message_sequence_value.as_json() == {
"Length": 2,
"Sequence_Field": [{"Byte": 5}, {"Byte": 6}],
}


def test_tlv_message_serialization(tlv_message_value: MessageValue) -> None:
tlv_message_value.set("Tag", "Msg_Data")
tlv_message_value.set("Length", 3)
tlv_message_value.set("Value", b"abc")
assert tlv_message_value.valid_message
assert tlv_message_value.as_json() == {"Length": 3, "Tag": "Msg_Data", "Value": "616263"}
27 changes: 27 additions & 0 deletions tests/unit/pyrflx_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1405,3 +1405,30 @@ def test_parameterized_message_invalid_type(parameterized_package: Package) -> N
"Message",
{"Length": bytes(8)}, # type: ignore[dict-item]
)


def test_json_serialization() -> None:
integer_value = IntegerValue(ModularInteger("Test::Int", expr.Number(256)))
integer_value.assign(128)
assert integer_value.as_json() == 128

enum_value = EnumValue(
Enumeration(
"Test::Enum",
[("One", expr.Number(1)), ("Two", expr.Number(2))],
expr.Number(8),
always_valid=False,
)
)
enum_value.assign("Two")
assert enum_value.as_json() == ("Two", 2)

sequence_value = SequenceValue(
Sequence("Test::ModularSequence", ModularInteger("Test::Int", expr.Number(256)))
)
sequence_value.assign([integer_value, integer_value, integer_value])
assert sequence_value.as_json() == [128, 128, 128]

opaque_value = OpaqueValue(Opaque())
opaque_value.assign(b"RecordFlux")
assert opaque_value.as_json() == b"RecordFlux"

0 comments on commit 2dc796b

Please sign in to comment.