Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix unknown enum handling #853

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 23 additions & 12 deletions protobuf/lib/src/protobuf/proto3_json.dart
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ void _mergeFromProto3Json(
ignoreUnknownFields, supportNamesWithUnderscores, permissiveEnums);

void recursionHelper(Object? json, _FieldSet fieldSet) {
// Convert a JSON object to proto object. Returns `null` on unknown enum
// values when [ignoreUnknownFields] is [true].
Object? convertProto3JsonValue(Object value, FieldInfo fieldInfo) {
final fieldType = fieldInfo.type;
switch (PbFieldType._baseType(fieldType)) {
Expand All @@ -174,14 +176,12 @@ void _mergeFromProto3Json(
throw context.parseException('Expected bool value', json);
case PbFieldType._BYTES_BIT:
if (value is String) {
Uint8List result;
try {
result = base64Decode(value);
return base64Decode(value);
} on FormatException {
throw context.parseException(
'Expected bytes encoded as base64 String', json);
}
return result;
}
throw context.parseException(
'Expected bytes encoded as base64 String', value);
Expand Down Expand Up @@ -264,14 +264,12 @@ void _mergeFromProto3Json(
case PbFieldType._SFIXED64_BIT:
if (value is int) return Int64(value);
if (value is String) {
Int64 result;
try {
result = Int64.parseInt(value);
return Int64.parseInt(value);
} on FormatException {
throw context.parseException(
'Expected int or stringified int', value);
}
return result;
}
throw context.parseException(
'Expected int or stringified int', value);
Expand Down Expand Up @@ -368,9 +366,12 @@ void _mergeFromProto3Json(
throw context.parseException('Expected a String key', subKey);
}
context.addMapIndex(subKey);
fieldValues[decodeMapKey(subKey, mapFieldInfo.keyFieldType)] =
convertProto3JsonValue(
subValue, mapFieldInfo.valueFieldInfo);
final key = decodeMapKey(subKey, mapFieldInfo.keyFieldType);
final value = convertProto3JsonValue(
subValue, mapFieldInfo.valueFieldInfo);
if (value != null) {
fieldValues[key] = value;
}
context.popIndex();
});
} else {
Expand All @@ -382,7 +383,10 @@ void _mergeFromProto3Json(
for (var i = 0; i < value.length; i++) {
final entry = value[i];
context.addListIndex(i);
values.add(convertProto3JsonValue(entry, fieldInfo));
final parsedValue = convertProto3JsonValue(entry, fieldInfo);
if (parsedValue != null) {
values.add(parsedValue);
}
context.popIndex();
}
} else {
Expand All @@ -402,8 +406,15 @@ void _mergeFromProto3Json(
original.mergeFromMessage(parsedSubMessage);
}
} else {
fieldSet._setFieldUnchecked(
meta, fieldInfo, convertProto3JsonValue(value, fieldInfo));
final parsedValue = convertProto3JsonValue(value, fieldInfo);
if (parsedValue == null) {
// Unknown enum
if (!ignoreUnknownFields) {
throw context.parseException('Unknown enum value', value);
}
} else {
fieldSet._setFieldUnchecked(meta, fieldInfo, parsedValue);
}
}
context.popIndex();
});
Expand Down
1 change: 1 addition & 0 deletions protoc_plugin/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ TEST_PROTO_LIST = \
entity \
enum_extension \
enum_name \
enum_test \
extend_unittest \
ExtensionEnumNameConflict \
ExtensionNameConflict \
Expand Down
16 changes: 16 additions & 0 deletions protoc_plugin/test/protos/enum_test.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

syntax = "proto3";

enum A {
X = 0;
Y = 1;
}

message Message {
A enum_field = 1;
map<int32, A> map_value_field = 2;
repeated A repeated_enum_field = 3;
}
40 changes: 40 additions & 0 deletions protoc_plugin/test/unknown_enums_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:test/test.dart';

import '../out/protos/enum_test.pb.dart';

void main() {
group('Enum parsing in maps, lists, messages', () {
test('Parse known fields', () {
final json = {
'enumField': 'Y',
'mapValueField': {'1': 'Y'},
'repeatedEnumField': ['Y'],
};

final msg = Message();
msg.mergeFromProto3Json(json);
expect(msg.enumField, A.Y);
expect(msg.mapValueField.values.toList(), [A.Y]);
expect(msg.repeatedEnumField, [A.Y]);
});

test('Skip unknown fields', () {
final json = {
'enumField': 'Z',
'mapValueField': {'1': 'X', '2': 'Z', '3': 'Y'},
'repeatedEnumField': ['X', 'Z', 'Y'],
};

final msg = Message();
msg.enumField = A.Y;
msg.mergeFromProto3Json(json, ignoreUnknownFields: true);
expect(msg.enumField, A.Y);
expect(msg.mapValueField.values.toList(), [A.X, A.Y]);
expect(msg.repeatedEnumField, [A.X, A.Y]);
});
});
}