Skip to content

Commit b43a184

Browse files
authored
Merge pull request #3314 from tejasna/tejasna.mapOptionsMultipleFields
Fix crash when inlined option map values have multiple fields
2 parents 10d8b20 + 6125839 commit b43a184

File tree

2 files changed

+345
-2
lines changed
  • wire-schema/src

2 files changed

+345
-2
lines changed

wire-schema/src/commonMain/kotlin/com/squareup/wire/schema/Options.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -388,8 +388,9 @@ class Options(
388388
// if `retainedValue` is a map, its value represents an inline message, and we need to
389389
// mark the proto member.
390390
if (retainedValue is Map<*, *>) {
391-
val (k, v) = retainedValue.entries.single()
392-
map[k as ProtoMember] = v!!
391+
for ((k, v) in retainedValue) {
392+
map[k as ProtoMember] = v!!
393+
}
393394
}
394395
continue
395396
}

wire-schema/src/jvmTest/kotlin/com/squareup/wire/schema/PrunerTest.kt

Lines changed: 342 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3671,6 +3671,348 @@ class PrunerTest {
36713671
val bookType = pruned.getType("Book") as MessageType
36723672
assertThat(bookType.field("title")).isNotNull()
36733673
}
3674+
3675+
@Test
3676+
fun rootCanHandleInlinedOptionWithMapValuesHavingMultipleFields() {
3677+
val schema = buildSchema {
3678+
add(
3679+
"test.proto".toPath(),
3680+
"""
3681+
|syntax = "proto3";
3682+
|
3683+
|import "google/protobuf/descriptor.proto";
3684+
|
3685+
|package wire.issue;
3686+
|
3687+
|message Options {
3688+
| map<string, ConfigPayload> config = 1;
3689+
| map<string, SettingPayload> setting = 2;
3690+
|}
3691+
|
3692+
|message ConfigPayload {
3693+
| optional string data = 1;
3694+
| optional string extra = 2;
3695+
|}
3696+
|
3697+
|message SettingPayload {
3698+
| optional string data = 1;
3699+
| optional string extra = 2;
3700+
|}
3701+
|
3702+
|extend google.protobuf.MessageOptions {
3703+
| repeated Options opt = 80000;
3704+
|}
3705+
|
3706+
|message SomeMessage {
3707+
| option (wire.issue.opt) = {
3708+
| config: [
3709+
| {
3710+
| key: "some_config_key_1"
3711+
| value: {
3712+
| data: "some_config_data_1"
3713+
| extra: "some_config_extra_1"
3714+
| }
3715+
| },
3716+
| ],
3717+
| setting: [
3718+
| {
3719+
| key: "some_setting_key_1"
3720+
| value: {
3721+
| data: "some_setting_data_1"
3722+
| extra: "some_setting_extra_1"
3723+
| }
3724+
| },
3725+
| {
3726+
| key: "some_setting_key_2"
3727+
| value: {
3728+
| data: "some_setting_data_2"
3729+
| extra: "some_setting_extra_2"
3730+
| }
3731+
| }
3732+
| ],
3733+
| };
3734+
|
3735+
| string id = 1;
3736+
|}
3737+
""".trimMargin(),
3738+
)
3739+
}
3740+
val pruned = schema.prune(
3741+
PruningRules.Builder()
3742+
.addRoot("wire.issue.Options#config")
3743+
.build(),
3744+
)
3745+
assertThat(pruned.protoFile("test.proto")!!.toSchema())
3746+
.isEqualTo(
3747+
"""
3748+
|// Proto schema formatted by Wire, do not edit.
3749+
|// Source: test.proto
3750+
|
3751+
|syntax = "proto3";
3752+
|
3753+
|package wire.issue;
3754+
|
3755+
|message Options {
3756+
| map<string, ConfigPayload> config = 1;
3757+
|}
3758+
|
3759+
|message ConfigPayload {
3760+
| optional string data = 1;
3761+
|
3762+
| optional string extra = 2;
3763+
|}
3764+
|
3765+
""".trimMargin(),
3766+
)
3767+
}
3768+
3769+
@Ignore("Pruning inlined map options is not supported")
3770+
@Test
3771+
fun pruneCanHandleInlinedOptionMemberWithMapValuesHavingMultipleFields() {
3772+
val schema = buildSchema {
3773+
add(
3774+
"test.proto".toPath(),
3775+
"""
3776+
|syntax = "proto3";
3777+
|
3778+
|import "google/protobuf/descriptor.proto";
3779+
|
3780+
|package wire.issue;
3781+
|
3782+
|message Options {
3783+
| map<string, ConfigPayload> config = 1;
3784+
| map<string, SettingPayload> setting = 2;
3785+
|}
3786+
|
3787+
|message ConfigPayload {
3788+
| optional string data = 1;
3789+
| optional string extra = 2;
3790+
|}
3791+
|
3792+
|message SettingPayload {
3793+
| optional string data = 1;
3794+
| optional string extra = 2;
3795+
|}
3796+
|
3797+
|extend google.protobuf.MessageOptions {
3798+
| repeated Options opt = 80000;
3799+
|}
3800+
|
3801+
|message SomeMessage {
3802+
| option (wire.issue.opt) = {
3803+
| config: [
3804+
| {
3805+
| key: "some_config_key_1"
3806+
| value: {
3807+
| data: "some_config_data_1"
3808+
| extra: "some_config_extra_1"
3809+
| }
3810+
| },
3811+
| ],
3812+
| setting: [
3813+
| {
3814+
| key: "some_setting_key_1"
3815+
| value: {
3816+
| data: "some_setting_data_1"
3817+
| extra: "some_setting_extra_1"
3818+
| }
3819+
| },
3820+
| {
3821+
| key: "some_setting_key_2",
3822+
| value: {
3823+
| data: "some_setting_data_2"
3824+
| extra: "some_setting_extra_2"
3825+
| }
3826+
| },
3827+
| ]
3828+
| };
3829+
|
3830+
| string id = 1;
3831+
|}
3832+
""".trimMargin(),
3833+
)
3834+
}
3835+
val pruned = schema.prune(
3836+
PruningRules.Builder()
3837+
.prune("wire.issue.Options#config")
3838+
.build(),
3839+
)
3840+
assertThat(pruned.protoFile("test.proto")!!.toSchema())
3841+
.isEqualTo(
3842+
"""
3843+
|// Proto schema formatted by Wire, do not edit.
3844+
|// Source: test.proto
3845+
|
3846+
|syntax = "proto3";
3847+
|
3848+
|package wire.issue;
3849+
|
3850+
|import "google/protobuf/descriptor.proto";
3851+
|
3852+
|message Options {
3853+
| map<string, SettingPayload> setting = 2;
3854+
|}
3855+
|
3856+
|message SettingPayload {
3857+
| optional string data = 1;
3858+
|
3859+
| optional string extra = 2;
3860+
|}
3861+
|
3862+
|message SomeMessage {
3863+
| option (wire.issue.opt) = {
3864+
| setting: [
3865+
| {
3866+
| key: "some_setting_key_1",
3867+
| value: {
3868+
| data: "some_setting_data_1",
3869+
| extra: "some_setting_extra_1"
3870+
| }
3871+
| },
3872+
| {
3873+
| key: "some_setting_key_2",
3874+
| value: {
3875+
| data: "some_setting_data_2",
3876+
| extra: "some_setting_extra_2"
3877+
| }
3878+
| }
3879+
| ]
3880+
| };
3881+
|
3882+
| string id = 1;
3883+
|}
3884+
|
3885+
|extend google.protobuf.MessageOptions {
3886+
| repeated Options opt = 80000;
3887+
|}
3888+
|
3889+
""".trimMargin(),
3890+
)
3891+
}
3892+
3893+
@Ignore("Pruning inlined map options is not supported")
3894+
@Test
3895+
fun pruneCanHandleInlinedOptionTypeWithMapValuesHavingMultipleFields() {
3896+
val schema = buildSchema {
3897+
add(
3898+
"test.proto".toPath(),
3899+
"""
3900+
|syntax = "proto3";
3901+
|
3902+
|import "google/protobuf/descriptor.proto";
3903+
|
3904+
|package wire.issue;
3905+
|
3906+
|message Options {
3907+
| map<string, ConfigPayload> config = 1;
3908+
| map<string, SettingPayload> setting = 2;
3909+
|}
3910+
|
3911+
|message ConfigPayload {
3912+
| optional string data = 1;
3913+
| optional string extra = 2;
3914+
|}
3915+
|
3916+
|message SettingPayload {
3917+
| optional string data = 1;
3918+
| optional string extra = 2;
3919+
|}
3920+
|
3921+
|extend google.protobuf.MessageOptions {
3922+
| optional Options opt = 80000;
3923+
|}
3924+
|
3925+
|message SomeMessage {
3926+
| option (wire.issue.opt) = {
3927+
| config: [
3928+
| {
3929+
| key: "some_config_key_1",
3930+
| value: {
3931+
| data: "some_config_data_1"
3932+
| extra: "some_config_extra_1"
3933+
| }
3934+
| },
3935+
| ],
3936+
| setting: [
3937+
| {
3938+
| key: "some_setting_key_1",
3939+
| value: {
3940+
| data: "some_setting_data_1"
3941+
| extra: "some_setting_extra_1"
3942+
| }
3943+
| },
3944+
| {
3945+
| key: "some_setting_key_2",
3946+
| value: {
3947+
| data: "some_setting_data_2",
3948+
| extra: "some_setting_extra_2"
3949+
| }
3950+
| },
3951+
| ],
3952+
| };
3953+
|
3954+
| string id = 1;
3955+
|}
3956+
""".trimMargin(),
3957+
)
3958+
}
3959+
val pruned = schema.prune(
3960+
PruningRules.Builder()
3961+
.prune("wire.issue.ConfigPayload")
3962+
.build(),
3963+
)
3964+
assertThat(pruned.protoFile("test.proto")!!.toSchema())
3965+
.isEqualTo(
3966+
"""
3967+
|// Proto schema formatted by Wire, do not edit.
3968+
|// Source: test.proto
3969+
|
3970+
|syntax = "proto3";
3971+
|
3972+
|package wire.issue;
3973+
|
3974+
|import "google/protobuf/descriptor.proto";
3975+
|
3976+
|message Options {
3977+
| map<string, SettingPayload> setting = 2;
3978+
|}
3979+
|
3980+
|message SettingPayload {
3981+
| optional string data = 1;
3982+
|
3983+
| optional string extra = 2;
3984+
|}
3985+
|
3986+
|message SomeMessage {
3987+
| option (wire.issue.opt) = {
3988+
| setting: [
3989+
| {
3990+
| key: "some_setting_key_1",
3991+
| value: {
3992+
| data: "some_setting_data_1",
3993+
| extra: "some_setting_extra_1"
3994+
| }
3995+
| },
3996+
| {
3997+
| key: "some_setting_key_2",
3998+
| value: {
3999+
| data: "some_setting_data_2",
4000+
| extra: "some_setting_extra_2"
4001+
| }
4002+
| }
4003+
| ]
4004+
| };
4005+
|
4006+
| string id = 1;
4007+
|}
4008+
|
4009+
|extend google.protobuf.MessageOptions {
4010+
| optional Options opt = 80000;
4011+
|}
4012+
|
4013+
""".trimMargin(),
4014+
)
4015+
}
36744016
}
36754017

36764018
// Used so that spotless or the IDE doesn't trim them away.

0 commit comments

Comments
 (0)