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

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

このコミットは、Go言語のテストスイートにおけるビットローテーション関連のテストと、特定のバグ修正テストの実行方法を改善するものです。具体的には、これまで手動での実行が必要だったテストを、Goの標準テスト実行フローに統合し、より自動化された形で実行できるように変更しています。

コミット

commit 578f24d5321401b9bb8686fa5e968c8bc63b89f6
Author: Rémy Oudompheng <oudomphe@phare.normalesup.org>
Date:   Fri Jan 11 22:42:55 2013 +0100

    test: add rotate.go and fixedbugs/bug313
    
    Update #4139.
    
    R=golang-dev, iant
    CC=golang-dev
    https://golang.org/cl/7094047

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

https://github.com/golang/go/commit/578f24d5321401b9bb8686fa5e968c8bc63b89f6

元コミット内容

このコミットの元のメッセージは以下の通りです。

test: add rotate.go and fixedbugs/bug313

Update #4139.

R=golang-dev, iant
CC=golang-dev
https://golang.org/cl/7094047

これは、rotate.gofixedbugs/bug313 というテストを追加(または修正・統合)し、Issue #4139 に関連する更新であることを示しています。また、Go Gerrit のチェンジリスト 7094047 を参照しています。

変更の背景

Go言語のテストスイートは、言語の安定性と正確性を保証するために非常に重要です。特に、ビット演算のような低レベルな操作は、異なるアーキテクチャやコンパイラの最適化によって予期せぬ挙動を示す可能性があるため、徹底的なテストが必要です。

このコミット以前は、test/rotate.gotest/fixedbugs/bug313.go のような一部のテストは、Goの標準テスト実行スクリプト (test/run.goall.bash) によって自動的に実行されず、手動での実行が必要でした。これは、テストの網羅性を低下させ、開発者がこれらの重要なテストの実行を忘れがちになるという問題がありました。

Issue #4139 の具体的な内容は不明ですが、コミット内容から推測すると、ビットローテーションのテストカバレッジの不足、または特定のコンパイラバグ(bug313)の再現性に関する問題が指摘されていた可能性があります。このコミットの目的は、これらのテストをGoのCI/CDパイプラインに完全に統合し、自動的に実行されるようにすることで、テストの信頼性と効率性を向上させることにあります。

前提知識の解説

このコミットを理解するためには、以下のGo言語のテストに関する前提知識が必要です。

  1. Go言語のテスト実行メカニズム:

    • Goのテストは通常 go test コマンドで実行されますが、Goプロジェクトのルートディレクトリにある test/run.go スクリプトは、より複雑なテストシナリオ(例えば、コンパイラやリンカのテスト、特定の環境変数設定が必要なテストなど)を管理するための内部的なテストハーネスとして機能します。
    • test/run.go は、プロジェクト内の様々なテストファイルを検出し、それぞれのテストタイプ(コンパイルエラーチェック、実行結果の検証など)に応じて適切な方法で実行します。
    • all.bash スクリプトは、Goプロジェクト全体のテストを実行するための最上位のスクリプトであり、内部的に test/run.go を呼び出します。
  2. Goテストファイルの特殊なコメントディレクティブ:

    • // skip: このコメントがファイルの先頭にある場合、test/run.go はそのファイルをテストとして実行しません。これは、特定の環境でのみ実行されるテストや、手動での実行を意図したテストに使用されます。
    • // runoutput <command>: このディレクティブは、テストファイル自体を直接コンパイル・実行するのではなく、指定された <command> を実行し、その標準出力(stdout)をGoのソースコードとして扱い、それをコンパイル・実行してテスト結果を検証することを意味します。これは、テストコードを動的に生成するシナリオで非常に有用です。
    • // errorcheckdir: このディレクティブは、そのテストファイルが存在するディレクトリ内のGoソースコードが、コンパイル時に特定のエラー(またはエラー群)を発生させることを期待するテストに使用されます。エラーが発生しない場合、テストは失敗します。これは、コンパイラのバグや特定の不正なコードパターンを検出するために使われます。
  3. ビットローテーション (Bit Rotation):

    • ビットローテーションは、ビット列を循環的にシフトする操作です。例えば、8ビットの 00001011 を左に1ビットローテーションすると 00010110 になります。最上位ビットが最下位ビットに、またはその逆へと移動します。
    • Go言語では、ビットローテーションは組み込み関数としては提供されていませんが、コンパイラは特定のパターン(例えば、シフトとOR演算の組み合わせ)をビットローテーション命令に最適化することがあります。この最適化が正しく機能するかどうかを検証するために、様々なビット幅やシフト量でのテストが必要です。

技術的詳細

このコミットの技術的な変更点は以下の通りです。

  1. test/rotate.go の役割変更と統合:

    • 以前の test/rotate.go は、// $G $D/$F.go && $L $F.$A && ... のようなシェルコマンドを直接記述しており、手動でコンパイル・実行する必要がありました。また、test/run.goskipOkay マップに登録されており、自動テストから除外されていました。
    • このコミットでは、test/rotate.go の先頭に // skip ディレクティブが追加され、このファイル自体は直接テストとして実行されないようになりました。
    • 代わりに、test/rotate.go は、ビットローテーションのテストケースを動的に生成する「テストジェネレータ」としての役割に特化しました。このファイルは、main 関数内で gentest 関数を呼び出し、様々な整数型 (int8, uint8, int16, uint16 など) とモード(ローテーションの方向や符号付き/なし)に基づいてテストコードを生成します。
    • test/rotate0.go, test/rotate1.go, test/rotate2.go, test/rotate3.go という4つの新しいファイルが追加されました。これらのファイルはそれぞれ const mode = X を定義し、先頭に // runoutput ./rotate.go ディレクティブを持っています。
    • これにより、test/run.go がこれらの新しいファイルを実行する際、まず test/rotate.go が実行され、その出力が実際のテストコードとしてコンパイル・実行されるという、動的なテスト生成・実行フローが確立されました。mode 定数によって、rotate.go が生成するテストコードのバリエーションが制御されます。
  2. test/fixedbugs/bug313.go の統合:

    • test/fixedbugs/bug313.go も以前は手動実行が必要で、test/run.goskipOkay マップに登録されていました。
    • このコミットでは、ファイルの先頭のコメントが // errchk ... から // errorcheckdir に変更されました。これは、このテストが特定のコンパイルエラーを期待するディレクトリベースのテストであることを示します。
    • test/run.goskipOkay マップから fixedbugs/bug313.go が削除されたことで、このテストも標準のテストスイートに統合され、自動的に実行されるようになりました。
  3. test/run.go の変更:

    • test/run.go 内の skipOkay マップから rotate.gofixedbugs/bug313.go のエントリが削除されました。これは、これらのテストがもはやスキップされるべきではなく、Goの標準テスト実行プロセスの一部として扱われるべきであることを明示しています。

これらの変更により、Goのテストスイートはより堅牢になり、ビットローテーションの正確性や特定のコンパイラバグの回帰テストが自動的に行われるようになりました。

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

このコミットで変更された主要なファイルとコードスニペットは以下の通りです。

  1. test/fixedbugs/bug313.go:

    --- a/test/fixedbugs/bug313.go
    +++ b/test/fixedbugs/bug313.go
    @@ -1,7 +1,4 @@
    -// errchk $G -e $D/$F.dir/[ab].go
    -// NOTE: This test is not run by 'run.go' and so not run by all.bash.
    -// To run this test you must use the ./run shell script.
    +// errorcheckdir
    
    • // errchk コメントが // errorcheckdir に変更され、手動実行に関するコメントが削除されました。
  2. test/rotate.go:

    --- a/test/rotate.go
    +++ b/test/rotate.go
    @@ -1,9 +1,6 @@
    -// $G $D/$F.go && $L $F.$A &&
    -// ./$A.out >tmp.go && $G tmp.go && $L -o $A.out1 tmp.$A && ./$A.out1
    -// rm -f tmp.go $A.out1
    +// skip
    
    -// NOTE: This test is not run by 'run.go' and so not run by all.bash.
    -// To run this test you must use the ./run shell script.
    +// NOTE: the actual tests to run are rotate[0123].go
    
     // Copyright 2012 The Go Authors.  All rights reserved.
     // Use of this source code is governed by a BSD-style
    @@ -12,8 +9,8 @@
     // Generate test of shift and rotate by constants.
     // The output is compiled and run.
     //
    -// The output takes around a gigabyte of memory to compile, link, and run
    -// but it is only done during ./run, not in normal builds using run.go.
    +// The integer type depends on the value of mode (rotate direction,
    +// signedness).
     
     package main
     
    @@ -37,9 +34,7 @@ func main() {
     		typ := fmt.Sprintf("int%d", 1<<logBits)
     		fmt.Fprint(b, strings.Replace(checkFunc, "XXX", typ, -1))
     		fmt.Fprint(b, strings.Replace(checkFunc, "XXX", "u"+typ, -1))
    -		for mode := 0; mode < 1<<2; mode++ {
    -			gentest(b, 1<<logBits, mode&1 != 0, mode&2 != 0)
    -		}
    +		gentest(b, 1<<logBits, mode&1 != 0, mode&2 != 0)
     	}
     }
    
    • 先頭に // skip が追加され、手動実行に関するコメントが削除されました。
    • main 関数内の for ループが削除され、gentest の呼び出しがループの外に出されました。これは、mode 定数が外部から提供されるようになったためです。
  3. test/rotate0.go, test/rotate1.go, test/rotate2.go, test/rotate3.go (新規ファイル):

    // runoutput ./rotate.go
    
    // Copyright 2013 The Go Authors.  All rights reserved.
    // Use of this source code is governed by a BSD-style
    // license that can be found in the LICENSE file.
    
    // Generate test of bit rotations.
    // The output is compiled and run.
    
    package main
    
    const mode = 0 // (or 1, 2, 3 for other files)
    
    • 各ファイルは // runoutput ./rotate.go ディレクティブと、異なる mode 定数を定義しています。
  4. test/run.go:

    --- a/test/run.go
    +++ b/test/run.go
    @@ -724,12 +724,10 @@ func (t *test) wantedErrors(file, short string) (errs []wantedError) {
     
     var skipOkay = map[string]bool{
     	"linkx.go":               true,
    -"rotate.go":              true,
     	"sigchld.go":             true,
     	"sinit.go":               true,
     	"fixedbugs/bug248.go":    true, // combines errorcheckdir and rundir in the same dir.
     	"fixedbugs/bug302.go":    true, // tests both .$O and .a imports.
    -"fixedbugs/bug313.go":    true, // errorcheckdir with failures in the middle.
     	"fixedbugs/bug345.go":    true, // needs the appropriate flags in gc invocation.
     	"fixedbugs/bug369.go":    true, // needs compiler flags.
     	"fixedbugs/bug385_32.go": true, // arch-specific errors.
    
    • skipOkay マップから rotate.gofixedbugs/bug313.go が削除されました。

コアとなるコードの解説

このコミットの核心は、Goのテストシステムにおける特殊なコメントディレクティブを効果的に活用し、テストの自動化と統合を実現した点にあります。

  • test/rotate.go の変革:

    • 以前は、test/rotate.go はそれ自体が実行可能なテストスクリプトであり、その内部で複数のテストケースを生成・実行していました。しかし、その実行は test/run.go からはスキップされていました。
    • 変更後、test/rotate.go は純粋な「テストコードジェネレータ」となりました。ファイルの先頭に // skip が追加されたことで、test/run.go はこのファイルを直接テストとして実行しなくなります。
    • main 関数内の for ループが削除されたのは、mode 定数が外部の呼び出し元(rotate0.go など)によって設定されるようになったためです。これにより、rotate.go は特定の mode に応じたテストコードを生成する単一目的のプログラムとして機能します。
  • rotate[0-3].go によるテストのトリガー:

    • 新しく追加された rotate0.gorotate1.gorotate2.gorotate3.go は、それぞれ異なる mode 定数(0から3)を定義しています。
    • これらのファイルの先頭にある // runoutput ./rotate.go ディレクティブが重要です。test/run.go がこれらのファイルを見つけると、まず ./rotate.go コマンドを実行します。このコマンドの標準出力は、Goのソースコードとして扱われ、その場でコンパイル・実行されます。
    • 例えば、rotate0.go が実行されると、test/rotate.gomode = 0 の設定で実行され、その結果生成されたテストコードがコンパイル・実行されます。これにより、rotate.go が生成する様々なビットローテーションテストが、Goの標準テストスイートに完全に統合され、自動的に実行されるようになりました。
  • fixedbugs/bug313.goerrorcheckdir への移行:

    • fixedbugs/bug313.go は、特定のコンパイルエラーを検出するためのテストです。以前は手動で errchk コマンドを使って実行する必要がありました。
    • // errorcheckdir ディレクティブは、test/run.go に対して、このテストが特定のディレクトリ内のコードがコンパイルエラーを引き起こすことを期待していることを伝えます。test/run.go は、このディレクティブに基づいて、適切なコンパイルチェックを実行し、期待されるエラーが発生するかどうかを検証します。
    • これにより、このバグ修正テストも自動テストスイートに組み込まれ、回帰テストとして機能するようになりました。
  • test/run.goskipOkay マップの更新:

    • skipOkay マップから rotate.gofixedbugs/bug313.go が削除されたことは、これらのテストがもはや「スキップしても良い」テストではなく、Goのテストスイートの不可欠な部分として扱われるべきであることを明確に示しています。

これらの変更は、Go言語のテストインフラストラクチャの成熟を示しており、より複雑なテストシナリオを自動化し、テストカバレッジと信頼性を向上させるための効果的なパターンを確立しています。

関連リンク

  • Go Gerrit チェンジリスト 7094047: https://golang.org/cl/7094047
    • : このチェンジリストのタイトルは「cmd/go: fix go get -u all」となっており、本コミットの変更内容(テストの追加・修正)とは直接関連しないように見えます。これは、チェンジリストがより広範な変更の一部であったか、あるいは参照されているチェンジリスト番号が異なる変更セットのものである可能性を示唆しています。しかし、コミットメッセージに明記されているため、Goの内部的なレビュープロセスの一部として参照されていると考えられます。

参考にした情報源リンク

  • Go言語の公式ドキュメント (特にテストに関するセクション)
  • Go言語のソースコード (特に test/ ディレクトリ内のファイルと cmd/go/test.go など)
  • Go言語のIssueトラッカー (Issue #4139 の具体的な内容を特定できなかったため、一般的なGoのIssueの性質から推測)
  • Go言語のGerritコードレビューシステム (チェンジリストの構造と役割の理解のため)