Skip to content

Commit 2653f60

Browse files
authored
Fix decoding of maps to match conformance tests (#391)
* Fix decoding of maps to match conformance tests * fix warning in test * fix regression test name * improve code styles, ensure booleans correct
1 parent 65faf65 commit 2653f60

File tree

2 files changed

+26
-2
lines changed

2 files changed

+26
-2
lines changed

lib/protobuf/decoder.ex

+20-2
Original file line numberDiff line numberDiff line change
@@ -233,8 +233,17 @@ defmodule Protobuf.Decoder do
233233
%FieldProps{type: type, map?: map?, oneof: oneof, name_atom: name_atom, repeated?: repeated?} =
234234
prop
235235

236-
embedded_msg = decode(bin, type)
237-
val = if map?, do: %{embedded_msg.key => embedded_msg.value}, else: embedded_msg
236+
embed_msg = decode(bin, type)
237+
238+
val =
239+
if map? do
240+
key = if is_nil(embed_msg.key), do: map_default(prop, :key), else: embed_msg.key
241+
value = if is_nil(embed_msg.value), do: map_default(prop, :value), else: embed_msg.value
242+
%{key => value}
243+
else
244+
embed_msg
245+
end
246+
238247
val = if oneof, do: {name_atom, val}, else: val
239248

240249
cond do
@@ -255,6 +264,15 @@ defmodule Protobuf.Decoder do
255264
end
256265
end
257266

267+
defp map_default(prop, key_or_value) do
268+
prop.type.__message_props__().field_props
269+
|> Enum.find(fn {_key, field_props} -> field_props.name_atom == key_or_value end)
270+
|> then(fn {_key, field_props} ->
271+
# Conformance only works when we use proto3 defaults here, even for proto2...
272+
Protobuf.DSL.field_default(:proto3, field_props)
273+
end)
274+
end
275+
258276
defp deep_merge(_oneof1 = {tag1, val1}, oneof2 = {tag2, val2}, props) do
259277
if tag1 == tag2 do
260278
# If the field is a oneof, we merge its value and keep the tag.

test/protobuf/conformance_regressions_test.exs

+6
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,12 @@ defmodule Protobuf.ConformanceRegressionsTest do
8383

8484
@describetag message_type: "protobuf_test_messages.proto3.TestAllTypesProto3"
8585

86+
test "Required.Proto2.ProtobufInput.ValidDataMap.INT32.INT32.MissingDefault.JsonOutput" do
87+
mod = ProtobufTestMessages.Proto2.TestAllTypesProto2
88+
problematic_payload = <<194, 3, 0>>
89+
assert %{map_int32_int32: %{0 => 0}} = mod.decode(problematic_payload)
90+
end
91+
8692
test "Required.Proto3.JsonInput.Int32FieldQuotedExponentialValue.JsonOutput" do
8793
mod = ProtobufTestMessages.Proto3.TestAllTypesProto3
8894
problematic_payload = ~S({"optionalInt32": "1e5"})

0 commit comments

Comments
 (0)