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

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

このコミットは、Go言語の標準ライブラリであるcrypto/tlsパッケージとfmtパッケージ内のテストコードにおける出力(print)に関する修正を目的としています。具体的には、テスト失敗時に表示されるエラーメッセージのフォーマットが不適切であったり、引数が不足していたりする箇所を修正し、より正確で分かりやすいデバッグ情報が提供されるように改善しています。

コミット

commit 663a7716a1dfda2fe8cb0d62647e549cb424d428
Author: Robert Hencke <robert.hencke@gmail.com>
Date:   Mon Mar 12 12:04:45 2012 +0900

    crypto/tls, fmt: print fixes
    
    R=golang-dev, bradfitz, minux.ma, rsc, bradfitz
    CC=golang-dev
    https://golang.org/cl/5787069

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

https://github.com/golang/go/commit/663a7716a1dfda2fe8cb0d62647e549cb424d428

元コミット内容

crypto/tlsパッケージとfmtパッケージのテストコードにおける出力(print)に関する修正。

変更の背景

Go言語のテストフレームワークでは、testingパッケージが提供され、テストの失敗を報告するためにt.Errorfのような関数が使用されます。これらの関数は、fmt.Printfと同様にフォーマット文字列とそれに続く引数を受け取ります。

このコミットが行われた背景には、以下の2つの問題があったと考えられます。

  1. crypto/tls/root_test.goにおけるエラーメッセージの引数不足: TestCertHostnameVerifyWindowsというテスト関数内で、証明書の検証が失敗した場合にt.Errorfが呼び出されていました。元のコードでは、フォーマット文字列に2つのプレースホルダー(%vが2つ)があるにもかかわらず、引数が1つしか渡されていませんでした。これにより、エラーメッセージが正しくフォーマットされず、デバッグ時に必要な情報が欠落する可能性がありました。Goのfmtパッケージのフォーマット関数は、引数の数がフォーマット指定子と一致しない場合に実行時エラー(panic)を引き起こすことはありませんが、期待通りの出力が得られないという問題が発生します。

  2. fmt/fmt_test.goにおけるIsSpaceテストの引数誤り: TestIsSpaceというテスト関数内で、t.Errorfの呼び出しにおいて、IsSpace(i)の結果をフォーマット文字列の引数として渡すべき箇所に、誤ってIsSpace(i)の呼び出し自体を渡していました。これにより、エラーメッセージが期待する値ではなく、関数の呼び出し結果がそのまま表示されてしまい、デバッグの妨げになっていました。特に、%Uフォーマット指定子はUnicodeコードポイントを表示するために使用されるため、rune型のiを渡すのが適切です。

これらの問題は、テストが失敗した際に開発者が問題を特定し、修正するための情報が不十分であったり、誤解を招く可能性があったため、修正が必要とされました。

前提知識の解説

Go言語のテスト

Go言語には標準でテストフレームワークが組み込まれており、testingパッケージを使用します。

  • テストファイルの命名規則: テストファイルは通常、テスト対象のファイル名に_test.goを付けた形式で命名されます(例: foo.goに対するfoo_test.go)。
  • テスト関数の命名規則: テスト関数はTestで始まり、その後に続く名前の最初の文字が大文字である必要があります(例: func TestMyFunction(t *testing.T))。
  • *testing.T: テスト関数は*testing.T型の引数を受け取ります。このオブジェクトを通じて、テストの失敗報告、ログ出力、ヘルパー関数の呼び出しなどを行います。
  • t.Errorf(...): テストが失敗したことを報告し、指定されたフォーマット文字列と引数を使用してエラーメッセージを出力します。テストの実行は継続されます。
  • t.Fatalf(...): テストが失敗したことを報告し、エラーメッセージを出力した後、テストの実行を即座に停止します。

fmtパッケージ

fmtパッケージは、Go言語におけるフォーマットI/Oを実装します。C言語のprintfscanfに似た機能を提供します。

  • fmt.Printf(format string, a ...interface{}) (n int, err error): 指定されたフォーマット文字列に従って引数をフォーマットし、標準出力に出力します。
  • フォーマット指定子:
    • %v: 値をデフォルトのフォーマットで出力します。
    • %U: Unicodeコードポイント(U+XXXX形式)を出力します。
    • %T: 値の型を出力します。

crypto/tlsパッケージ

crypto/tlsパッケージは、TLS (Transport Layer Security) プロトコルを実装し、安全なネットワーク通信を提供します。これは、HTTPSなどのセキュアな通信の基盤となります。

  • TLSハンドシェイク: クライアントとサーバー間で安全な通信チャネルを確立するためのプロセスです。これには、証明書の交換と検証が含まれます。
  • 証明書検証: クライアントまたはサーバーが、通信相手から提示されたデジタル証明書が信頼できるかどうかを確認するプロセスです。これには、ホスト名の検証(証明書に記載されたホスト名が接続先のホスト名と一致するか)が含まれます。
  • x509.HostnameError: crypto/x509パッケージで定義されているエラー型で、証明書のホスト名検証が失敗した場合に返されます。

unicodeパッケージ

unicodeパッケージは、Unicode文字のプロパティを扱うための関数を提供します。

  • unicode.IsSpace(r rune) bool: 指定されたルーン(Unicodeコードポイント)が空白文字であるかどうかを判定します。

技術的詳細

このコミットは、Go言語のテストコードにおける2つの具体的な問題を修正しています。

  1. src/pkg/crypto/tls/root_test.goの修正: 元のコードでは、t.Errorf("should fail to verify for example.com: %v", addr, err)という行がありました。ここで、フォーマット文字列には2つの%vプレースホルダーがありますが、引数として渡されているのはaddrerrの2つです。しかし、よく見ると、元のコードはt.Errorf("should fail to verify for example.com: %v", addr, err)ではなく、t.Errorf("should fail to verify for example.com: %v", addr, err)となっており、errが2つ目の引数として渡されていませんでした。 修正前: t.Errorf("should fail to verify for example.com: %v", addr, err) 修正後: t.Errorf("should fail to verify for example.com: %v", addr) この修正により、フォーマット文字列のプレースホルダーの数と引数の数が一致するようになり、エラーメッセージが正しくフォーマットされるようになりました。具体的には、errが不要な引数として削除されました。これは、おそらく元の意図がaddrのみを表示することであったか、あるいはerrが常にx509.HostnameError型であり、その情報が既に_, ok := err.(x509.HostnameError)で処理されているため、エラーメッセージに含める必要がなかったためと考えられます。

  2. src/pkg/fmt/fmt_test.goの修正: 元のコードでは、t.Errorf("isSpace(%U) = %v, want %v", IsSpace(i), unicode.IsSpace(i))という行がありました。ここで、最初の%UはUnicodeコードポイントを表示するためのフォーマット指定子です。しかし、引数としてIsSpace(i)(これはbool型の結果)が渡されていました。%Urune型(Unicodeコードポイント)を期待するため、これは型ミスマッチであり、期待通りの出力が得られません。 修正前: t.Errorf("isSpace(%U) = %v, want %v", IsSpace(i), unicode.IsSpace(i)) 修正後: t.Errorf("isSpace(%U) = %v, want %v", i, IsSpace(i), unicode.IsSpace(i)) この修正により、最初の%Uには正しいrune型の変数iが渡されるようになり、エラーメッセージが正確に「isSpace(U+XXXX) = <実際の値>, want <期待する値>」という形式で表示されるようになりました。これにより、どのUnicode文字でIsSpace関数が期待通りに動作しなかったのかが明確になります。

これらの修正は、Go言語のテストコードの品質とデバッグのしやすさを向上させるための、細かではあるが重要な改善です。

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

diff --git a/src/pkg/crypto/tls/root_test.go b/src/pkg/crypto/tls/root_test.go
index 8dcf74ea72..e61c218512 100644
--- a/src/pkg/crypto/tls/root_test.go
+++ b/src/pkg/crypto/tls/root_test.go
@@ -50,7 +50,7 @@ func TestCertHostnameVerifyWindows(t *testing.T) {
 		conn, err := Dial("tcp", addr+":443", cfg)
 		if err == nil {
 			conn.Close()
-			t.Errorf("should fail to verify for example.com: %v", addr, err)
+			t.Errorf("should fail to verify for example.com: %v", addr)
 			continue
 		}
 		_, ok := err.(x509.HostnameError)
diff --git a/src/pkg/fmt/fmt_test.go b/src/pkg/fmt/fmt_test.go
index 8c5afccac5..758fc50d08 100644
--- a/src/pkg/fmt/fmt_test.go
+++ b/src/pkg/fmt/fmt_test.go
@@ -835,7 +835,7 @@ func TestIsSpace(t *testing.T) {
 	// IsSpace = isSpace is defined in export_test.go.
 	for i := rune(0); i <= unicode.MaxRune; i++ {\n 	\tif IsSpace(i) != unicode.IsSpace(i) {\n-\t\t\tt.Errorf("isSpace(%U) = %v, want %v", IsSpace(i), unicode.IsSpace(i))\n+\t\t\tt.Errorf("isSpace(%U) = %v, want %v", i, IsSpace(i), unicode.IsSpace(i))\n \t\t}\n \t}\n }\n```

## コアとなるコードの解説

### `src/pkg/crypto/tls/root_test.go`の変更

*   **変更前**:
    ```go
    t.Errorf("should fail to verify for example.com: %v", addr, err)
    ```
    この行では、フォーマット文字列`"should fail to verify for example.com: %v"`に対して、`addr`と`err`の2つの引数を渡そうとしていました。しかし、フォーマット文字列には`%v`が1つしかありません。これは、`fmt.Errorf`(`t.Errorf`が内部的に使用)が期待する引数の数と実際の引数の数が一致しない状況でした。Goの`fmt`パッケージは、このような場合にパニックを起こすことはありませんが、`err`引数は無視されるか、意図しない出力になる可能性がありました。

*   **変更後**:
    ```go
    t.Errorf("should fail to verify for example.com: %v", addr)
    ```
    `err`引数が削除されました。これにより、フォーマット文字列のプレースホルダーの数(1つ)と引数の数(`addr`の1つ)が一致し、エラーメッセージが正しくフォーマットされるようになりました。この修正は、エラーメッセージの意図が`addr`のみを表示することであったことを示唆しています。

### `src/pkg/fmt/fmt_test.go`の変更

*   **変更前**:
    ```go
    t.Errorf("isSpace(%U) = %v, want %v", IsSpace(i), unicode.IsSpace(i))
    ```
    この行では、最初のフォーマット指定子`%U`に対して、`IsSpace(i)`の戻り値(`bool`型)が引数として渡されていました。`%U`はUnicodeコードポイント(`rune`型)を期待するため、これは誤った引数の渡し方でした。結果として、エラーメッセージの`%U`の部分が正しく表示されず、デバッグ情報が不十分でした。

*   **変更後**:
    ```go
    t.Errorf("isSpace(%U) = %v, want %v", i, IsSpace(i), unicode.IsSpace(i))
    ```
    最初の`%U`に対して、ループ変数である`rune`型の`i`が正しく渡されるようになりました。これにより、エラーメッセージは「`isSpace(U+XXXX) = <実際のIsSpace(i)の結果>, want <期待するunicode.IsSpace(i)の結果>`」という形式で出力されるようになり、どのUnicode文字でテストが失敗したのかが明確に示されるようになりました。

これらの変更は、テストコードの出力の正確性を高め、テスト失敗時のデバッグを容易にすることを目的としています。

## 関連リンク

*   Go言語公式ドキュメント: [https://go.dev/doc/](https://go.dev/doc/)
*   `testing`パッケージ: [https://pkg.go.dev/testing](https://pkg.go.dev/testing)
*   `fmt`パッケージ: [https://pkg.go.dev/fmt](https://pkg.go.dev/fmt)
*   `crypto/tls`パッケージ: [https://pkg.go.dev/crypto/tls](https://pkg.go.dev/crypto/tls)
*   `unicode`パッケージ: [https://pkg.go.dev/unicode](https://pkg.go.dev/unicode)

(注: コミットメッセージに記載されていた`https://golang.org/cl/5787069`のリンクは、現在のGo Gerritシステムでは見つかりませんでした。これは、古いCL番号であるか、または参照が変更された可能性があります。)

## 参考にした情報源リンク

*   コミットの差分情報(`git diff`の出力)
*   Go言語の公式ドキュメント(`testing`, `fmt`, `crypto/tls`, `unicode`パッケージ)
*   Go言語のテストに関する一般的な知識
*   `fmt.Printf`のフォーマット指定子に関する知識