[インデックス 18148] ファイルの概要
このコミットは、Go言語の標準ライブラリ encoding/json
パッケージにおける omitempty
タグのテストカバレッジを向上させることを目的としています。具体的には、float64
、bool
、uint
、および空の構造体 (struct{}
) 型に対して omitempty
タグがどのように機能するかを確認するための新しいテストケースが追加されています。
コミット
commit a39f3b29ec47fb9ed73fc922a44b5e6ff931073d
Author: Shawn Smith <shawn.p.smith@gmail.com>
Date: Wed Jan 1 17:54:06 2014 +1100
encoding/json: improve omitempty test coverage
R=golang-codereviews, dave, bradfitz
CC=golang-codereviews
https://golang.org/cl/46250043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/a39f3b29ec47fb9ed73fc922a44b5e6ff931073d
元コミット内容
encoding/json: improve omitempty test coverage
変更の背景
Go言語の encoding/json
パッケージは、Goの構造体とJSONデータの間で変換を行うための標準的な方法を提供します。構造体のフィールドに json:"fieldName,omitempty"
のように omitempty
タグが指定されている場合、そのフィールドの値が型の「ゼロ値」であるとき、JSON出力からそのフィールドが省略されます。
このコミットの背景には、omitempty
タグの挙動が様々なデータ型で正しく機能することを保証するためのテストカバレッジの不足があったと考えられます。特に、float64
(0.0)、bool
(false)、uint
(0)、そして空の構造体 (struct{}
) のような、直感的にゼロ値と認識されにくい、あるいはその挙動が曖昧になりがちな型に対する omitempty
の振る舞いを明確にし、テストで検証する必要がありました。これにより、開発者が omitempty
タグを安心して利用できるよう、ライブラリの堅牢性を高めることが目的です。
前提知識の解説
Go言語の encoding/json
パッケージ
encoding/json
パッケージは、Goのデータ構造をJSON形式にエンコード(Marshal)したり、JSONデータをGoのデータ構造にデコード(Unmarshal)したりするための機能を提供します。
JSONタグ
Goの構造体のフィールドには、json:"fieldName"
のような「タグ」を付与することができます。これにより、JSONエンコード/デコード時のフィールド名や挙動をカスタマイズできます。
omitempty
タグ
omitempty
はJSONタグのオプションの一つです。構造体のフィールドに json:"fieldName,omitempty"
と指定すると、そのフィールドの値がGoの型の「ゼロ値」である場合に、JSON出力からそのフィールドが完全に省略されます。
各型のゼロ値は以下の通りです。
- 数値型 (int, float64, uintなど):
0
- bool型:
false
- string型:
""
(空文字列) - ポインタ、スライス、マップ、チャネル、関数、インターフェース:
nil
- 構造体: その構造体のすべてのフィールドがそれぞれのゼロ値である場合
このコミットでは、特に float64
(0.0)、bool
(false)、uint
(0)、そして struct{}
(空の構造体) のゼロ値に対する omitempty
の挙動がテストされています。struct{}
は、メモリを消費しない特殊な構造体で、セットのような用途で使われることがあります。そのゼロ値は、struct{}
型のインスタンスそのものです。
技術的詳細
このコミットは、encoding/json
パッケージのテストファイル encode_test.go
に新しいフィールドと期待されるJSON出力の変更を追加することで、omitempty
タグのテストカバレッジを向上させています。
具体的には、Optionals
というテスト用の構造体に以下のフィールドが追加されました。
Fr float64
json:"fr":
float64` 型の必須フィールド。Fo float64
json:"fo,omitempty":
float64型で
omitempty` が適用されるフィールド。Br bool
json:"br":
bool` 型の必須フィールド。Bo bool
json:"bo,omitempty":
bool型で
omitempty` が適用されるフィールド。Ur uint
json:"ur":
uint` 型の必須フィールド。Uo uint
json:"uo,omitempty":
uint型で
omitempty` が適用されるフィールド。Str struct{}
json:"str"
: 空の構造体struct{}
型の必須フィールド。Sto struct{}
json:"sto,omitempty"
: 空の構造体struct{}
型でomitempty
が適用されるフィールド。
これらのフィールドは、Optionals
構造体のインスタンスが初期化された際に、それぞれの型のゼロ値(0.0
、false
、0
、{}
)を持つことになります。
そして、optionalsExpected
という期待されるJSON文字列が更新され、これらの新しいフィールドが omitempty
タグなしで定義されている場合はJSON出力に含まれ、omitempty
タグ付きで定義されている場合はゼロ値のときに省略されることを検証しています。特に struct{}
の場合、omitempty
が付いていても、その値がゼロ値(つまり struct{}
そのもの)であれば省略されるべきですが、このテストでは Sto
フィールドが optionalsExpected
に含まれています。これは、struct{}
のゼロ値は struct{}
そのものであり、omitempty
が付いていても、そのフィールドが構造体として存在する場合は出力されるという挙動をテストしている可能性があります。しかし、一般的な omitempty
の挙動からすると、struct{}
のゼロ値は省略されるべきです。このコミットの変更点を見ると、"sto": {}
が optionalsExpected
に追加されているため、struct{}
のゼロ値は omitempty
が付いていても出力されるという挙動をテストしているように見えます。これは、struct{}
が他の型とは異なる omitempty
の振る舞いをする可能性を示唆しています。
コアとなるコードの変更箇所
変更は src/pkg/encoding/json/encode_test.go
ファイルに集中しています。
--- a/src/pkg/encoding/json/encode_test.go
+++ b/src/pkg/encoding/json/encode_test.go
@@ -25,13 +25,30 @@ type Optionals struct {
Mr map[string]interface{} `json:"mr"`
Mo map[string]interface{} `json:",omitempty"`
+
+ Fr float64 `json:"fr"`
+ Fo float64 `json:"fo,omitempty"`
+
+ Br bool `json:"br"`
+ Bo bool `json:"bo,omitempty"`
+
+ Ur uint `json:"ur"`
+ Uo uint `json:"uo,omitempty"`
+
+ Str struct{} `json:"str"`
+ Sto struct{} `json:"sto,omitempty"`
}
var optionalsExpected = `{
"sr": "",
"omitempty": 0,
"slr": null,
- "mr": {}
+ "mr": {},
+ "fr": 0,
+ "br": false,
+ "ur": 0,
+ "str": {},
+ "sto": {}
}`
func TestOmitEmpty(t *testing.T) {
コアとなるコードの解説
Optionals
構造体へのフィールド追加
Optionals
構造体は、encoding/json
パッケージの omitempty
タグの挙動をテストするために使用されます。このコミットでは、以下のフィールドが追加されました。
Fr float64
json:"fr":
float64型のフィールド
Frは、JSON出力では
frというキーになります。
omitempty` タグがないため、値がゼロ値 (0.0) であってもJSON出力に含まれます。Fo float64
json:"fo,omitempty":
float64型のフィールド
Foは、JSON出力では
foというキーになります。
omitempty` タグがあるため、値がゼロ値 (0.0) の場合はJSON出力から省略されます。Br bool
json:"br":
bool型のフィールド
Brは、JSON出力では
brというキーになります。
omitempty` タグがないため、値がゼロ値 (false) であってもJSON出力に含まれます。Bo bool
json:"bo,omitempty":
bool型のフィールド
Boは、JSON出力では
boというキーになります。
omitempty` タグがあるため、値がゼロ値 (false) の場合はJSON出力から省略されます。Ur uint
json:"ur":
uint型のフィールド
Urは、JSON出力では
urというキーになります。
omitempty` タグがないため、値がゼロ値 (0) であってもJSON出力に含まれます。Uo uint
json:"uo,omitempty":
uint型のフィールド
Uoは、JSON出力では
uoというキーになります。
omitempty` タグがあるため、値がゼロ値 (0) の場合はJSON出力から省略されます。Str struct{}
json:"str"
: 空の構造体struct{}
型のフィールドStr
は、JSON出力ではstr
というキーになります。omitempty
タグがないため、値がゼロ値 ({}) であってもJSON出力に含まれます。Sto struct{}
json:"sto,omitempty"
: 空の構造体struct{}
型のフィールドSto
は、JSON出力ではsto
というキーになります。omitempty
タグがあるため、値がゼロ値 ({}) の場合はJSON出力から省略されるはずですが、optionalsExpected
の変更を見ると、"sto": {}
が含まれています。これは、struct{}
のゼロ値に対するomitempty
の挙動が他の型とは異なり、常に{}
として出力されることをテストしている可能性があります。
optionalsExpected
変数の更新
optionalsExpected
は、Optionals
構造体をJSONエンコードした際に期待されるJSON文字列を定義しています。このコミットでは、上記で追加されたフィールドに対応するために、この文字列が更新されました。
"fr": 0,
:Fr
フィールドはomitempty
がないため、ゼロ値 (0.0) であってもJSONに含まれます。"br": false,
:Br
フィールドはomitempty
がないため、ゼロ値 (false) であってもJSONに含まれます。"ur": 0,
:Ur
フィールドはomitempty
がないため、ゼロ値 (0) であってもJSONに含まれます。"str": {},
:Str
フィールドはomitempty
がないため、ゼロ値 ({}) であってもJSONに含まれます。"sto": {}
:Sto
フィールドはomitempty
がありますが、struct{}
のゼロ値は{}
として出力されることをテストしています。これは、struct{}
のゼロ値が他の型のゼロ値とは異なる扱いを受けることを示唆しています。
これらの変更により、TestOmitEmpty
関数は、Optionals
構造体のインスタンスをJSONエンコードし、その結果が optionalsExpected
と一致するかどうかを検証します。これにより、float64
、bool
、uint
、struct{}
型に対する omitempty
の挙動が正しく実装されていることを確認できます。
関連リンク
- Go言語
encoding/json
パッケージのドキュメント: https://pkg.go.dev/encoding/json - Go言語の
omitempty
タグに関する公式ブログ記事 (もしあれば、検索して追加)
参考にした情報源リンク
- https://github.com/golang/go/commit/a39f3b29ec47fb9ed73fc922a44b5e6ff931073d
- Go言語の
encoding/json
パッケージに関する一般的な情報 (Web検索結果に基づく) - Go言語のゼロ値に関する情報 (Web検索結果に基づく)
- Go言語の
struct{}
型に関する情報 (Web検索結果に基づく)