~bigbes/tarantool

tarantool-protobuf

a2f1209d39dd42c812e515369ed21e39430048fb — Eugene Blikh 3 months ago 1712192
json: drop unrecognized enum string names per proto3 spec

decode_enum returned the raw input string for unknown enum names,
which then propagated through the codec and errored at encode time
with "unknown enum value '...'". For repeated and map fields the
spec requires *dropping* the element (not substituting 0), so the
encoded output should be shorter than the input.

decode_enum now returns nil for unrecognized names. The optional /
repeated / map call sites in decode_message skip nil values: optional
leaves the field unset (encoded as default), repeated compacts the
array, map omits the entry. Numeric and known-name inputs are
unchanged.

Drops 5 entries from test/conformance/known_failures.txt:
IgnoreUnknownEnumStringValueIn{Optional,Repeated,RepeatedPart,
MapPart,MapValue}.
2 files changed, 15 insertions(+), 9 deletions(-)

M runtime/pb/json.lua
M test/conformance/known_failures.txt
M runtime/pb/json.lua => runtime/pb/json.lua +15 -4
@@ 364,7 364,10 @@ local function decode_enum(enum_desc, v)
        local n = enum_desc.by_name[v]
        if n ~= nil then return n end
    end
    return tonumber(v) or v
    -- proto3 JSON: unrecognized integer enum values pass through; unrecognized
    -- string names yield nil so the caller can drop the element (repeated/map)
    -- or fall back to the field default (singular).
    return tonumber(v)
end

local function decode_field_value(field, v)


@@ 518,15 521,23 @@ decode_message = function(desc, v)
            if f.kind == 'map' then
                local m = {}
                for mk, mv in pairs(jv) do
                    m[decode_map_key(f.key, mk)] = decode_field_value(f.value, mv)
                    local dv = decode_field_value(f.value, mv)
                    if dv ~= nil then
                        m[decode_map_key(f.key, mk)] = dv
                    end
                end
                out[f.name] = m
            elseif f.repeated then
                local arr = {}
                for i = 1, #jv do arr[i] = decode_field_value(f, jv[i]) end
                local n = 0
                for i = 1, #jv do
                    local dv = decode_field_value(f, jv[i])
                    if dv ~= nil then n = n + 1; arr[n] = dv end
                end
                out[f.name] = arr
            else
                out[f.name] = decode_field_value(f, jv)
                local dv = decode_field_value(f, jv)
                if dv ~= nil then out[f.name] = dv end
            end
        end
        -- Unknown JSON keys are silently ignored (per spec).

M test/conformance/known_failures.txt => test/conformance/known_failures.txt +0 -5
@@ 19,11 19,6 @@
#
# Re-generate this file after fixes via `just conformance-refresh-failures`.
Recommended.Proto3.JsonInput.FieldNameWithDoubleUnderscores.ProtobufOutput
Recommended.Proto3.JsonInput.IgnoreUnknownEnumStringValueInMapPart.ProtobufOutput
Recommended.Proto3.JsonInput.IgnoreUnknownEnumStringValueInMapValue.ProtobufOutput
Recommended.Proto3.JsonInput.IgnoreUnknownEnumStringValueInOptionalField.ProtobufOutput
Recommended.Proto3.JsonInput.IgnoreUnknownEnumStringValueInRepeatedField.ProtobufOutput
Recommended.Proto3.JsonInput.IgnoreUnknownEnumStringValueInRepeatedPart.ProtobufOutput
Recommended.Proto3.JsonInput.NullValueInOtherOneofOldFormat.Validator
Recommended.Proto3.ProtobufInput.RejectInvalidUtf8.String.MapKey
Recommended.Proto3.ProtobufInput.RejectInvalidUtf8.String.MapValue