😽

protoを比較しようとしてcmp.Diffでcmpops.IgnoreUnexportedを設定してもエラーになるとき

2020/10/12に公開

go でテストを書いていると、struct と struct の比較に google/go-cmpをよく使う

概ね問題なく使えるのだが struct の field に private な field があると外部 package から参照できず panic してしまう

consider using a custom Comparer; if you control the implementation of type, you can also consider using an Exporter, AllowUnexported, or cmpopts.IgnoreUnexported [recovered]

こんな感じのエラー表示される

エラーメッセージに表示されているとおり cmpopts.IgnoreUnexported option を使えば、だいたいの場合で問題ない

if diff := cmp.Diff(got, want, cmpopts.IgnoreUnexported()); diff != "" {
  t.Errorf("(-got +want)\n%v", diff)
}

で、今回は表題の通り cmpopts.IgnoreUnexported を設定しても以前として panic してしまう

        "google.golang.org/protobuf/types/known/timestamppb".Timestamp
consider using a custom Comparer; if you control the implementation of type, you can also consider using an Exporter, AllowUnexported, or cmpopts.IgnoreUnexported

色々調べてみると google.golang.org/protobuf/testing/protocmp package の Transform メソッドを使うとよいということが分かった

The google.protobuf.Any message is automatically unmarshaled such that the "value" field is a Message representing the underlying message value assuming it could be resolved and properly unmarshaled.
This does not directly transform higher-order composite Go types. For example, []*foopb.Message is not transformed into []Message, but rather the individual message elements of the slice are transformed.

ブログを読むとproto の API が変わったためらしい

最終的には以下のコードで上手くいった

if diff := cmp.Diff(got, want, protocmp.Transform()); diff != "" {
  t.Errorf("(-got +want)\n%v", diff)
}

参考になれば

Discussion