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

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

このコミットは、Go言語の標準ライブラリである net/http パッケージ内のテストファイルにおける軽微な修正(nits)を目的としています。具体的には、go tool vet という静的解析ツールによって検出された、fmt.Errorf および t.Fatalf のフォーマット文字列と引数の不一致を修正しています。

コミット

commit 27b98974964e9fd5d25ebef96b4ba11b99aaa8e1
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date:   Thu May 15 12:41:45 2014 -0700

    net/http: fix nits found by go tool vet
    
    LGTM=ruiu
    R=golang-codereviews, ruiu
    CC=golang-codereviews
    https://golang.org/cl/91480043

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/27b98974964e9fd5d25ebef96b4ba11b99aaa8e1

元コミット内容

net/http: fix nits found by go tool vet

LGTM=ruiu
R=golang-codereviews, ruiu
CC=golang-codereviews
https://golang.org/cl/91480043

変更の背景

このコミットの背景には、Go言語の開発におけるコード品質と堅牢性の維持があります。go tool vet は、Goのソースコードを静的に解析し、潜在的なバグや疑わしいコード構造を報告するツールです。これには、fmt.Printft.Errorf のようなフォーマット関数における引数の型とフォーマット指定子の不一致などが含まれます。

今回の変更は、net/http パッケージのテストコードにおいて、go tool vet が指摘したフォーマット文字列の誤用を修正するものです。テストコードは、ライブラリの正確な動作を保証するために非常に重要であり、そのテストコード自体が正確であることは、信頼性の高いソフトウェアを構築する上で不可欠です。go tool vet のようなツールを使用することで、開発者はこのような軽微ながらも潜在的な問題を見つけ出し、修正することができます。これにより、テストの出力がより正確になり、デバッグが容易になるというメリットがあります。

前提知識の解説

Go言語の fmt パッケージとフォーマット指定子

Go言語の fmt パッケージは、フォーマットされたI/O(入出力)を実装するための機能を提供します。fmt.Printffmt.Errorffmt.Sprintf など、多くの関数がC言語の printf に似たフォーマット文字列を使用します。フォーマット文字列には、以下のようなフォーマット指定子が含まれます。

  • %v: 値のデフォルトフォーマット。
  • %q: Goの構文に従ってクォートされた文字列。文字列リテラルとして安全に表示するために使用されます。
  • %d: 10進数。
  • %s: 文字列。

これらの指定子は、対応する引数の型と一致している必要があります。例えば、%q は文字列型の引数に対して使用されるべきであり、文字列ではないオブジェクトに対して使用すると、意図しない出力になったり、go tool vet によって警告されたりする可能性があります。

Go言語のテストフレームワーク (testing パッケージ)

Go言語には、標準ライブラリとして testing パッケージが提供されており、ユニットテストやベンチマークテストを記述するための機能を提供します。

  • *testing.T: テスト関数に渡される型で、テストの状態を管理し、エラーや失敗を報告するためのメソッドを提供します。
  • t.Errorf(format string, args ...interface{}): テスト中にエラーが発生したことを報告しますが、テストの実行は続行します。
  • t.Fatalf(format string, args ...interface{}): テスト中に致命的なエラーが発生したことを報告し、現在のテストの実行を停止します。

これらのメソッドも fmt パッケージと同様にフォーマット文字列と可変引数を受け取ります。

go tool vet

go tool vet は、Go言語のソースコードを静的に解析し、疑わしいコード構造を報告するコマンドラインツールです。これは、コンパイルエラーにはならないが、実行時に問題を引き起こす可能性のあるコードパターンや、一般的なプログラミングミスを検出するのに役立ちます。vet が検出する一般的な問題には以下のようなものがあります。

  • Printf 系の関数におけるフォーマット文字列と引数の不一致。
  • 構造体タグの誤り。
  • ロックの誤用。
  • 到達不能なコード。
  • 変数のシャドーイング。

go tool vet は、Go開発ワークフローの重要な一部であり、CI/CDパイプラインに組み込まれることも多く、コードレビューの前に基本的な品質チェックを行うのに役立ちます。

技術的詳細

このコミットは、net/http パッケージのテストファイルである serve_test.gotransport_test.go における t.Errorf および t.Fatalf の呼び出し方を修正しています。

src/pkg/net/http/serve_test.go の変更

元のコードでは、t.Errorf のフォーマット文字列 %q に対して、req という *http.Request 型の変数を直接渡していました。

// Original
t.Errorf("Code %d: Wanted %q Modified for %q: %s", code, req, got)

%q は通常、文字列をクォートして表示するために使用されます。*http.Request オブジェクトを %q でフォーマットしようとすると、go tool vet は警告を発する可能性があります。これは、*http.Requeststring 型ではないため、%q の意図する動作と合致しないためです。

修正後のコードでは、req の代わりに wantStatus という文字列型の変数を %q に対応させています。wantStatusfmt.Sprintf("%d %s", code, StatusText(code)) によって生成された、期待されるHTTPステータス行(例: "200 OK")を表す文字列です。

// Modified
t.Errorf("Code %d: Wanted %q Modified for %q: %s", code, wantStatus, req, got)

この変更により、エラーメッセージがより正確になり、go tool vet の警告が解消されます。エラーメッセージの意図としては、「期待されるステータス行」をクォートして表示したかったと考えられます。

src/pkg/net/http/transport_test.go の変更

元のコードでは、t.Fatalf のフォーマット文字列 %v%q に対して、両方とも fakeErr.Error() という文字列を渡していました。

// Original
t.Fatalf("Do error = %v; want something containing %q", fakeErr.Error())

%v は任意の値をデフォルトフォーマットで表示するために使用されますが、%q は文字列をクォートして表示します。この場合、fakeErr.Error() が2回渡されているため、引数の数がフォーマット指定子の数と一致していません。go tool vet はこのような引数の不足または過剰を検出します。

修正後のコードでは、最初の %v には実際の err オブジェクト(error インターフェース型)を渡し、2番目の %q には fakeErr.Error()(文字列型)を渡しています。

// Modified
t.Fatalf("Do error = %v; want something containing %q", err, fakeErr.Error())

これにより、t.Fatalf の引数がフォーマット文字列と正しく対応し、エラーメッセージが意図通りに表示されるようになります。%verr オブジェクト全体を表示し、%q で期待されるエラーメッセージの一部をクォートして表示するという、より適切なロギングが行われます。

これらの修正は、Goのテストコードの品質を向上させ、go tool vet のような静的解析ツールが提供する価値を最大限に活用する良い例です。

コアとなるコードの変更箇所

src/pkg/net/http/serve_test.go

--- a/src/pkg/net/http/serve_test.go
+++ b/src/pkg/net/http/serve_test.go
@@ -2144,7 +2144,7 @@ func TestCodesPreventingContentTypeAndBody(t *testing.T) {
 			got := ht.rawResponse(req)
 			wantStatus := fmt.Sprintf("%d %s", code, StatusText(code))
 			if !strings.Contains(got, wantStatus) {
-				t.Errorf("Code %d: Wanted %q Modified for %q: %s", code, req, got)
+				t.Errorf("Code %d: Wanted %q Modified for %q: %s", code, wantStatus, req, got)
 			} else if strings.Contains(got, "Content-Length") {
 				t.Errorf("Code %d: Got a Content-Length from %q: %s", code, req, got)
 			} else if strings.Contains(got, "stuff") {

src/pkg/net/http/transport_test.go

--- a/src/pkg/net/http/transport_test.go
+++ b/src/pkg/net/http/transport_test.go
@@ -2081,7 +2081,7 @@ func TestTransportClosesBodyOnError(t *testing.T) {
 		defer res.Body.Close()
 	}
 	if err == nil || !strings.Contains(err.Error(), fakeErr.Error()) {
-		t.Fatalf("Do error = %v; want something containing %q", fakeErr.Error())
+		t.Fatalf("Do error = %v; want something containing %q", err, fakeErr.Error())
 	}
 	select {
 	case err := <-readBody:

コアとなるコードの解説

src/pkg/net/http/serve_test.go の変更点

TestCodesPreventingContentTypeAndBody 関数内の t.Errorf の呼び出しが修正されました。

  • 変更前: t.Errorf("Code %d: Wanted %q Modified for %q: %s", code, req, got)
    • %q フォーマット指定子に対して req (*http.Request 型) が渡されていました。これは go tool vet によって不適切と判断される可能性がありました。*http.Request は文字列ではないため、%q でクォートしても期待通りの出力が得られないか、誤解を招く可能性があります。
  • 変更後: t.Errorf("Code %d: Wanted %q Modified for %q: %s", code, wantStatus, req, got)
    • %q フォーマット指定子に対して wantStatus (string 型) が渡されるようになりました。wantStatusfmt.Sprintf("%d %s", code, StatusText(code)) によって生成された、期待されるHTTPステータス行の文字列です。これにより、エラーメッセージがより正確になり、go tool vet の警告が解消されます。

src/pkg/net/http/transport_test.go の変更点

TestTransportClosesBodyOnError 関数内の t.Fatalf の呼び出しが修正されました。

  • 変更前: t.Fatalf("Do error = %v; want something containing %q", fakeErr.Error())
    • フォーマット文字列には %v%q の2つの指定子がありますが、引数として fakeErr.Error() (string 型) が1つしか渡されていませんでした。これは引数の数が不足しているため、go tool vet によって検出される典型的なエラーです。
  • 変更後: t.Fatalf("Do error = %v; want something containing %q", err, fakeErr.Error())
    • 最初の %v には実際の err オブジェクト(error インターフェース型)が渡され、2番目の %q には fakeErr.Error()string 型)が渡されるようになりました。これにより、フォーマット指定子と引数の数が一致し、エラーメッセージが意図通りに表示されるようになります。

これらの変更は、テストコードの可読性と正確性を向上させ、go tool vet のような静的解析ツールが提供するフィードバックを適切に組み込むことの重要性を示しています。

関連リンク

  • Go言語の fmt パッケージ: https://pkg.go.dev/fmt
  • Go言語の testing パッケージ: https://pkg.go.dev/testing
  • go tool vet のドキュメント (Goの公式ドキュメント内): go doc cmd/vet または go help vet で詳細を確認できます。

参考にした情報源リンク

  • Go言語の公式ドキュメント
  • go tool vet の一般的な使用例と検出パターンに関する情報
  • Go言語のテストに関するベストプラクティス
  • コミットメッセージと差分情報
  • Goのコードレビュープロセスに関する情報 (LGTM, R, CCなどの表記)