Skip to content

Commit

Permalink
Support json_name for proto2; Ensures proper field emission for JSON …
Browse files Browse the repository at this point in the history
…encoder (#390)

* Fix >500 conformance tests

- Makes proto2 also support json_name. This alone fixes >200 tests
- Ensures JSON encoder decides correctly when to emit or not emit fields (at the
very least, more correctly than before :))

* Remove dead test

* Remove exemption

* fix bad delete
  • Loading branch information
v0idpwn authored Dec 29, 2024
1 parent 9ff73ed commit 509460a
Show file tree
Hide file tree
Showing 4 changed files with 17 additions and 44 deletions.
1 change: 0 additions & 1 deletion conformance/exemptions.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
Recommended.Proto2.JsonInput.FieldNameExtension.Validator
Required.Proto2.JsonInput.StoresDefaultPrimitive.Validator
Recommended.Proto3.JsonInput.IgnoreUnknownEnumStringValueInMapValue.ProtobufOutput
Recommended.Proto3.JsonInput.IgnoreUnknownEnumStringValueInOptionalField.ProtobufOutput
Recommended.Proto3.JsonInput.IgnoreUnknownEnumStringValueInRepeatedField.ProtobufOutput
33 changes: 14 additions & 19 deletions lib/protobuf/json/encode.ex
Original file line number Diff line number Diff line change
Expand Up @@ -159,22 +159,14 @@ defmodule Protobuf.JSON.Encode do
:maps.from_list(regular ++ oneofs)
end

defp encode_regular_fields(struct, %{field_props: field_props}, opts) do
defp encode_regular_fields(struct, %{field_props: field_props, syntax: syntax}, opts) do
for {_field_num, %{name_atom: name, oneof: nil} = prop} <- field_props,
%{^name => value} = struct,
emit?(prop, value) || opts[:emit_unpopulated] do
emit?(syntax, prop, value) || opts[:emit_unpopulated] do
encode_field(prop, value, opts)
end
end

defp emit?(_prop, nil) do
false
end

defp emit?(prop, value) do
if default?(prop, value), do: prop.proto3_optional?, else: true
end

defp encode_oneof_fields(struct, message_props, opts) do
%{field_tags: field_tags, field_props: field_props, oneof: oneofs} = message_props

Expand Down Expand Up @@ -309,15 +301,18 @@ defmodule Protobuf.JSON.Encode do
defp maybe_repeat(%{repeated?: false}, val, fun), do: fun.(val)
defp maybe_repeat(%{repeated?: true}, val, fun), do: Enum.map(val, fun)

defp default?(_prop, +0.0), do: true
defp default?(_prop, nil), do: true
defp default?(_prop, 0), do: true
defp default?(_prop, false), do: true
defp default?(_prop, []), do: true
defp default?(_prop, ""), do: true
defp default?(_prop, %{} = map) when map_size(map) == 0, do: true
defp default?(%{type: {:enum, enum}}, key) when is_atom(key), do: enum.value(key) == 0
defp default?(_prop, _value), do: false
defp emit?(:proto2, %{default: value}, value), do: false
defp emit?(:proto2, %{optional?: true}, val), do: not is_nil(val)
defp emit?(:proto3, %{proto3_optional?: true}, val), do: not is_nil(val)
defp emit?(_syntax, _prop, +0.0), do: false
defp emit?(_syntax, _prop, nil), do: false
defp emit?(_syntax, _prop, 0), do: false
defp emit?(_syntax, _prop, false), do: false
defp emit?(_syntax, _prop, []), do: false
defp emit?(_syntax, _prop, ""), do: false
defp emit?(_syntax, _prop, %{} = map) when map_size(map) == 0, do: false
defp emit?(_syntax, %{type: {:enum, enum}}, key) when is_atom(key), do: enum.value(key) != 0
defp emit?(_syntax, _prop, _value), do: true

defp transform_module(message, module) do
if transform_module = module.transform_module() do
Expand Down
6 changes: 3 additions & 3 deletions lib/protobuf/protoc/generator/message.ex
Original file line number Diff line number Diff line change
Expand Up @@ -339,10 +339,10 @@ defmodule Protobuf.Protoc.Generator.Message do
end

# Omit `json_name` from the options list when it matches the original field
# name to keep the list small. Only Proto3 has JSON support for now.
defp add_json_name_to_opts(opts, :proto3, %{name: name, json_name: name}), do: opts
# name to keep the list small.
defp add_json_name_to_opts(opts, _, %{name: name, json_name: name}), do: opts

defp add_json_name_to_opts(opts, :proto3, %{json_name: json_name}),
defp add_json_name_to_opts(opts, _, %{json_name: json_name}),
do: Keyword.put(opts, :json_name, json_name)

defp add_json_name_to_opts(opts, _syntax, _props), do: opts
Expand Down
21 changes: 0 additions & 21 deletions test/protobuf/protoc/generator/message_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -731,27 +731,6 @@ defmodule Protobuf.Protoc.Generator.MessageTest do
assert msg =~ "field :simple, 1, type: :int32\n"
assert msg =~ "field :the_field_name, 2, type: :string, json_name: \"theFieldName\"\n"
end

test "is omitted when syntax is not proto3" do
ctx = %Context{}

desc = %Google.Protobuf.DescriptorProto{
name: "Foo",
field: [
%Google.Protobuf.FieldDescriptorProto{
name: "the_field_name",
json_name: "theFieldName",
number: 1,
type: :TYPE_STRING,
label: :LABEL_REQUIRED
}
]
}

{[], [{_mod, msg}]} = Generator.generate(ctx, desc)

assert msg =~ "field :the_field_name, 1, required: true, type: :string\n"
end
end

test "generate/2 repeated enum field" do
Expand Down

0 comments on commit 509460a

Please sign in to comment.