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

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

このコミットは、src/pkg/crypto/x509/pem_decrypt_test.go ファイルにおけるテスト出力のフォーマット文字列の誤りを修正するものです。具体的には、t.Logf 関数で使用されていたフォーマット動詞 %s が、期待される文字列型ではない x509.PEMCipher 型の値を表示しようとした際に発生する不適切な出力(%!s(x509.PEMCipher=1) のような形式)を修正し、汎用的な %v に変更することで、正しい値の表示を可能にしています。

コミット

commit 2ec3a0a72fbe2cdd4affc67383ae67c503e7469b
Author: Dmitriy Vyukov <dvyukov@google.com>
Date:   Thu Jul 3 12:08:24 2014 +0400

    crypto/x509: fix format strings in test
    Currently it says:
    --- PASS: TestDecrypt-2 (0.11s)
    pem_decrypt_test.go:17: test 0. %!s(x509.PEMCipher=1)
    --- PASS: TestEncrypt-2 (0.00s)
    pem_decrypt_test.go:42: test 0. %!s(x509.PEMCipher=1)
    
    LGTM=alex.brainman
    R=golang-codereviews, alex.brainman
    CC=golang-codereviews
    https://golang.org/cl/108400044

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

https://github.com/golang/go/commit/2ec3a0a72fbe2cdd4affc67383ae67c503e7469b

元コミット内容

crypto/x509: fix format strings in test
Currently it says:
--- PASS: TestDecrypt-2 (0.11s)
pem_decrypt_test.go:17: test 0. %!s(x509.PEMCipher=1)
--- PASS: TestEncrypt-2 (0.00s)
pem_decrypt_test.go:42: test 0. %!s(x509.PEMCipher=1)

LGTM=alex.brainman
R=golang-codereviews, alex.brainman
CC=golang-codereviews
https://golang.org/cl/108400044

変更の背景

このコミットの背景には、Go言語の標準ライブラリ crypto/x509 パッケージ内のテストコード pem_decrypt_test.go において、テストのログ出力が意図しない形式で表示される問題がありました。具体的には、t.Logf 関数(fmt.Printf と同様のフォーマット指定子を使用)で、data.kind という変数を %s フォーマット動詞で出力しようとしていました。しかし、data.kind は文字列型ではなく、x509.PEMCipher というカスタム型であったため、Goのフォーマットエンジンはこれを文字列として適切に変換できず、%!s(x509.PEMCipher=1) のようなエラーメッセージを出力していました。

この出力はテストの実行結果自体には影響しませんが、テストログの可読性を著しく損ない、デバッグやテスト結果の確認を困難にしていました。この問題を解決し、テストログをより分かりやすくするために、フォーマット動詞を汎用的な %v に変更する必要がありました。

前提知識の解説

Go言語の testing パッケージ

Go言語には、ユニットテストを記述するための標準パッケージ testing が用意されています。テスト関数は Test で始まる名前を持ち、*testing.T 型の引数を取ります。

  • t.Logf(format string, args ...interface{}): テスト中にログメッセージを出力するための関数です。fmt.Printf と同様のフォーマット指定子を使用できます。テストが成功した場合でも、このログは表示されます。
  • t.Error(args ...interface{}) / t.Errorf(format string, args ...interface{}): テストを失敗としてマークし、エラーメッセージを出力します。テストの実行は継続されます。
  • t.Fatal(args ...interface{}) / t.Fatalf(format string, args ...interface{}): テストを失敗としてマークし、エラーメッセージを出力した後、テストの実行を即座に停止します。

Go言語の fmt パッケージとフォーマット動詞

fmt パッケージは、Go言語におけるフォーマットI/Oを扱うための基本的なパッケージです。fmt.Printffmt.Sprintf、そして testing パッケージの t.Logf などで使われるフォーマット動詞は、出力する値の型に応じて適切なものを選択する必要があります。

主要なフォーマット動詞には以下のようなものがあります。

  • %d: 整数値を10進数で表示します。
  • %s: 文字列を表示します。
  • %v: 値をデフォルトのフォーマットで表示します。これは最も汎用的な動詞で、任意の型の値を適切に表示しようとします。構造体やカスタム型の場合、その型のデフォルトの文字列表現(通常はフィールド名と値)を出力します。
  • %T: 値の型を表示します。

今回の問題は、x509.PEMCipher 型の値を文字列として扱おうとしたために発生しました。%s は文字列型を期待するため、それ以外の型が渡されると、Goのランタイムは「この型は %s でフォーマットできません」という旨のエラーメッセージ(%!s(...))を出力します。

crypto/x509 パッケージ

crypto/x509 パッケージは、X.509証明書とPKIX(Public Key Infrastructure X.509)関連の機能をGo言語で提供する標準ライブラリです。証明書の解析、生成、検証、PEMエンコード/デコードなどの機能が含まれます。このコミットで修正された pem_decrypt_test.go は、PEM形式でエンコードされたデータの復号化に関するテストコードです。

技術的詳細

このコミットの技術的な核心は、Go言語のフォーマット動詞の適切な使用にあります。t.Logffmt.Printf と同じフォーマットルールに従います。

元のコードでは、t.Logf("test %d. %s", i, data.kind) と記述されていました。 ここで、i はループカウンタであり、整数型なので %d で問題ありません。 しかし、data.kindx509.PEMCipher 型であり、これは文字列型ではありません。x509.PEMCipher はおそらく列挙型のようなもので、内部的には整数値を持つカスタム型です。

Goの fmt パッケージのルールでは、%sstring 型、または String() string メソッドを実装している型に対して使用されます。x509.PEMCipher 型が String() string メソッドを実装していなかったため、%s を使用すると、Goランタイムは「この型は %s でフォーマットできません」ということを示す %!s(type=value) の形式で出力しました。

この問題を解決するために、フォーマット動詞を %v に変更しました。%v は「値のデフォルトフォーマット」を表し、任意の型の値を適切に表示しようとします。カスタム型の場合、通常はその型の内部表現(例えば、構造体のフィールド値)を人間が読める形式で出力します。これにより、x509.PEMCipher 型の値が期待通りに表示されるようになります。

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

--- a/src/pkg/crypto/x509/pem_decrypt_test.go
+++ b/src/pkg/crypto/x509/pem_decrypt_test.go
@@ -14,7 +14,7 @@ import (
 
 func TestDecrypt(t *testing.T) {
 	for i, data := range testData {
-		t.Logf("test %d. %s", i, data.kind)
+		t.Logf("test %v. %v", i, data.kind)
 		block, rest := pem.Decode(data.pemData)
 		if len(rest) > 0 {
 			t.Error("extra data")
@@ -39,7 +39,7 @@ func TestDecrypt(t *testing.T) {
 
 func TestEncrypt(t *testing.T) {
 	for i, data := range testData {
-		t.Logf("test %d. %s", i, data.kind)
+		t.Logf("test %v. %v", i, data.kind)
 		plainDER, err := base64.StdEncoding.DecodeString(data.plainDER)
 		if err != nil {
 			t.Fatal("cannot decode test DER data: ", err)

コアとなるコードの解説

変更は src/pkg/crypto/x509/pem_decrypt_test.go ファイルの2箇所にあります。

  1. TestDecrypt 関数内:

    • 変更前: t.Logf("test %d. %s", i, data.kind)
    • 変更後: t.Logf("test %v. %v", i, data.kind)
  2. TestEncrypt 関数内:

    • 変更前: t.Logf("test %d. %s", i, data.kind)
    • 変更後: t.Logf("test %v. %v", i, data.kind)

両方の変更において、t.Logf のフォーマット文字列が修正されています。

  • 最初の %d はループカウンタ i のためのものでしたが、これも汎用的な %v に変更されています。i は整数なので %d でも問題ありませんが、一貫性を持たせるためか、あるいは将来的に i が整数以外の型になる可能性を考慮して %v に変更されたと考えられます。%v は整数も適切に表示します。
  • 重要な変更は2番目のフォーマット動詞です。data.kindx509.PEMCipher 型であり、これが %s でフォーマットされるとエラーが発生していました。これを汎用的な %v に変更することで、x509.PEMCipher 型の値がそのデフォルトの文字列表現で正しく出力されるようになります。これにより、%!s(x509.PEMCipher=1) のような不適切な出力が解消され、テストログの可読性が向上します。

この修正は、機能的な変更ではなく、テストコードのログ出力の品質を改善するためのものです。

関連リンク

参考にした情報源リンク