go-cmp を使うと2つの構造体のDiffを取ることができるが、プロパティにJSON文字列([]byte
や json.RawMessage
など)があると、内容は同じでもインデント等が異なるとdiffが出てしまい、うまく比較できない。
type Hoge struct { ID string JSON json.RawMessage } func main() { a := Hoge{ID: "1", JSON: json.RawMessage(`{"a":1, "b":2}`)} b := Hoge{ID: "1", JSON: json.RawMessage(`{"b":2, "a":1}`)} diff := cmp.Diff(a, b) fmt.Println(diff) // diff がでる
この場合は、cmp.Transformer()
でJSON文字列をjson.Unmarshal()
して構造体に変換するようにして、cmp.Diff()
のオプションに渡すことで比較できるようになる1。
func CmpTransformJSON() cmp.Option { return cmp.FilterValues( func(x, y []byte) bool { return json.Valid(x) && json.Valid(y) }, cmp.Transformer("ParseJSON", func(in []byte) (out interface{}) { if err := json.Unmarshal(in, &out); err != nil { panic(err) } return out }), ) }
type Hoge struct { ID string JSON json.RawMessage } a := Hoge{ID: "1", JSON: json.RawMessage(`{"a":1, "b":2}`)} b := Hoge{ID: "1", JSON: json.RawMessage(`{"b":2, "a":1}`)} diff := cmp.Diff(a, b, CmpTransformJSON()) fmt.Println(diff) // diff がでない
まとめると以下のようになる。
package main import ( "encoding/json" "fmt" "github.com/google/go-cmp/cmp" ) type Hoge struct { ID string JSON json.RawMessage } func main() { a := Hoge{ID: "1", JSON: json.RawMessage(`{"a":1, "b":2}`)} b := Hoge{ID: "1", JSON: json.RawMessage(`{"b":2, "a":1}`)} { diff := cmp.Diff(a, b) fmt.Println("diff:", diff) // diff がでる } { diff := cmp.Diff(a, b, CmpTransformJSON()) fmt.Println("diff:", diff) // diff がでない } } func CmpTransformJSON() cmp.Option { return cmp.FilterValues( func(x, y []byte) bool { return json.Valid(x) && json.Valid(y) }, cmp.Transformer("ParseJSON", func(in []byte) (out interface{}) { if err := json.Unmarshal(in, &out); err != nil { panic(err) } return out }), ) }
環境
- Go:
1.9.3
- go-cmp:
0.5.9