Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 18148] ファイルの概要

このコミットは、Go言語の標準ライブラリ encoding/json パッケージにおける omitempty タグのテストカバレッジを向上させることを目的としています。具体的には、float64booluint、および空の構造体 (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.0false0{})を持つことになります。

そして、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 と一致するかどうかを検証します。これにより、float64booluintstruct{} 型に対する omitempty の挙動が正しく実装されていることを確認できます。

関連リンク

  • Go言語 encoding/json パッケージのドキュメント: https://pkg.go.dev/encoding/json
  • Go言語の omitempty タグに関する公式ブログ記事 (もしあれば、検索して追加)

参考にした情報源リンク