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

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

このコミットは、Go言語プロジェクトにおけるCGO(C言語との相互運用)テストの実行方法を刷新するものです。具体的には、misc/cgo/life および misc/cgo/stdio ディレクトリ内のCGOテストが、個別のシェルスクリプト(test.bash)に依存する形式から、Go言語で書かれた汎用テストランナーである test/run.go を利用する形式へと移行されました。これにより、テストインフラの統一と、将来的なWindows環境でのCGO stdio テストの有効化に向けた基盤が整備されました。

コミット

commit 1e95429c3fbfb9a30bd8a68e95bce4f882b40aec
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Tue Aug 7 09:38:35 2012 +0800

    misc/cgo/{life,stdio}, test/run.go: use test/run.go to do the cgo tests
       Enhances test/run.go to support testing other directories
       Will enable stdio tests on Windows in a follow-up CL.
    
    R=golang-dev, alex.brainman, rsc
    CC=golang-dev
    https://golang.org/cl/6220049

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

https://github.com/golang/go/commit/1e95429c3fbfb9a30bd8a68e95bce4f882b40aec

元コミット内容

このコミットの目的は、misc/cgo/{life,stdio} にあるCGOテストを、test/run.go を使用するように変更することです。これに伴い、test/run.go は他のディレクトリのテストもサポートするように機能拡張されました。将来的には、この変更によってWindows環境での stdio テストも有効にできるようになります。

変更の背景

Go言語のプロジェクトでは、様々な種類のテストが存在し、それぞれ異なる方法で実行されることがありました。特にCGO関連のテストは、C言語のコードをコンパイル・リンクする必要があるため、プラットフォーム固有のシェルスクリプト(test.bash)に依存しているケースが見られました。しかし、このような個別のスクリプトは、テスト実行の複雑性を増し、異なるOS環境(特にWindows)での互換性の問題を引き起こす可能性がありました。

このコミットの背景には、以下の課題意識があったと考えられます。

  1. テスト実行の統一化: 個別のシェルスクリプトに依存するのではなく、Go言語で書かれた単一のテストランナー (test/run.go) にテスト実行ロジックを集約することで、テストインフラの保守性を向上させ、一貫したテスト実行フローを確立したいという意図がありました。
  2. クロスプラットフォーム対応の強化: test.bash のようなシェルスクリプトはUnix系OSに特化しており、Windows環境でのテスト実行には別途 test.bat のようなバッチファイルが必要でした。test/run.go のようなGo言語製のツールに移行することで、Go言語のクロスプラットフォーム特性を活かし、より容易にWindowsを含む多様な環境でテストを実行できるようになります。コミットメッセージにある「Will enable stdio tests on Windows in a follow-up CL.」という記述は、この目的を明確に示しています。
  3. テストの柔軟性向上: test/run.go がディレクトリ単位でのテスト実行をサポートするように拡張されることで、特定のテストスイート全体を簡単に実行できるようになり、テストの管理と実行がより柔軟になります。
  4. テスト結果の標準化: golden.out ファイルを main.outrun.out にリネームし、新しい .out ファイルを追加していることから、テストの期待出力の管理方法も統一・標準化しようとしていることが伺えます。

これらの背景から、Goプロジェクト全体のテストインフラの健全性と効率性を高めるための戦略的な変更であったと言えます。

前提知識の解説

このコミットを理解するためには、以下の概念が重要です。

  1. CGO: Go言語とC言語のコードを相互運用するためのGoの機能です。GoプログラムからCライブラリを呼び出したり、CプログラムからGo関数を呼び出したりすることができます。CGOを使用するプログラムは、通常のGoプログラムとは異なるビルドプロセスを必要とし、Cコンパイラ(GCCなど)に依存します。
  2. Goのテストフレームワーク: Go言語には標準で testing パッケージが提供されており、ユニットテストやベンチマークテストを記述できます。しかし、Goプロジェクトの内部では、より複雑な統合テストやシステムテストのために、test/run.go のようなカスタムテストランナーが使用されることがあります。
  3. test/run.go: Goプロジェクトの内部で使用される、特定のテストシナリオを実行するためのカスタムテストランナーです。これはGoの標準テストフレームワークとは異なり、特定のディレクトリ内のGoファイルを実行し、その出力が期待される出力(golden.out.out ファイル)と一致するかどうかを検証するような、より高レベルなテストロジックを実装しています。
  4. シェルスクリプト (.bash, .bat): Unix系OSではBashスクリプト(.bash)、Windowsではバッチファイル(.bat)が、コマンドラインからの操作や自動化されたタスク実行によく用いられます。Goプロジェクトのテストでも、ビルド、実行、結果の比較といった一連の処理を自動化するためにこれらのスクリプトが使われていました。
  5. ゴールデンファイルテスト (Golden File Testing): テスト対象のプログラムが生成する出力(テキスト、画像など)を、事前に用意された「ゴールデンファイル」(期待される正しい出力を含むファイル)と比較することで、プログラムの動作が正しいことを検証するテスト手法です。出力が複雑でアサーションを記述しにくい場合や、出力の変更を視覚的に確認したい場合に有効です。このコミットでは、golden.out ファイルが main.outrun.out にリネームされ、新しい .out ファイルが追加されていることから、この手法が用いられていることがわかります。
  6. // skip および // cmpout ディレクティブ: Goのソースコード内に記述される特殊なコメントで、test/run.go のようなカスタムテストランナーによって解釈されるメタデータです。
    • // skip: このファイルまたはテストケースをテスト実行から除外することを示唆します。
    • // cmpout: このGoプログラムの実行結果を、対応する .out ファイルと比較して検証することを示唆します。これはゴールデンファイルテストの一種です。

技術的詳細

このコミットの技術的な変更は、主に以下の3つの側面から構成されます。

  1. テスト実行ロジックのGo言語への移行:

    • misc/cgo/life/test.bashmisc/cgo/stdio/test.bash という2つのシェルスクリプトが削除されました。これらのスクリプトは、CGOプログラムのビルド、実行、そしてその出力と golden.out ファイルとの比較を行っていました。
    • 代わりに、src/run.bashsrc/run.bat が変更され、CGOテストの実行に go run $GOROOT/test/run.go - . (Unix系) または go run %GOROOT%\test\run.go - ..\misc\cgo\life (Windows) の形式で test/run.go を呼び出すようになりました。これにより、テスト実行の制御がGo言語製のツールに一元化されます。
  2. test/run.go の機能拡張:

    • test/run.go は、コマンドライン引数の解析ロジックが大幅に強化されました。以前は個別の .go ファイルのみを引数として受け取っていましたが、この変更により、ディレクトリパスも引数として受け取れるようになりました。
    • fi, err := os.Stat(arg); err == nil && fi.IsDir() のチェックが追加され、引数がディレクトリであるかどうかが判断されます。
    • もし引数がディレクトリであれば、goFiles(arg) 関数(コミット差分には含まれていませんが、ディレクトリ内のGoファイルを列挙する関数と推測されます)を使ってそのディレクトリ内のすべてのGoファイルを検出し、それぞれに対して startTest を呼び出すようになりました。
    • 引数が .go ファイルであれば、filepath.Split を使ってディレクトリとファイル名に分割し、startTest を呼び出します。
    • これにより、test/run.gogo run run.go - ./fixedbugs のように、特定のディレクトリ内のすべてのテストを実行できるようになり、テストの管理がより柔軟になりました。
    • また、log.Fatalf("can't yet deal with non-directory and non-go file %q", arg) というエラーメッセージが追加され、.go ファイルでもディレクトリでもない引数に対してはエラーを出すようになりました。これは、test/run.go が処理できる入力の範囲を明確にしています。
  3. テスト出力ファイルの管理とディレクティブの導入:

    • misc/cgo/life/golden.outmisc/cgo/life/main.out にリネームされました。
    • misc/cgo/stdio/golden.outmisc/cgo/stdio/run.out にリネームされました。
    • misc/cgo/stdio/chain.out, misc/cgo/stdio/fib.out, misc/cgo/stdio/hello.out といった新しい .out ファイルが追加されました。これらは、対応するCGOプログラムの期待される出力を格納するゴールデンファイルとして機能します。
    • misc/cgo/life/life.gomisc/cgo/stdio/file.go// skip コメントが追加されました。これは test/run.go がこれらのファイルをテスト対象から除外するための指示であると考えられます。
    • misc/cgo/life/main.go, misc/cgo/stdio/chain.go, misc/cgo/stdio/fib.go, misc/cgo/stdio/hello.go// cmpout コメントが追加されました。これは test/run.go がこれらのGoプログラムを実行し、その標準出力が対応する .out ファイルの内容と一致するかどうかを比較検証するための指示であると考えられます。

これらの変更により、GoプロジェクトのCGOテストは、より統一され、クロスプラットフォーム対応が強化され、柔軟な実行が可能となるテストインフラへと進化しました。

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

このコミットにおけるコアとなるコードの変更箇所は、主に test/run.go と、テスト実行スクリプトである src/run.bash および src/run.bat です。

test/run.go の変更点

--- a/test/run.go
+++ b/test/run.go
@@ -77,16 +77,23 @@ func main() {
 	if flag.NArg() > 0 {
 		for _, arg := range flag.Args() {
 			if arg == "-" || arg == "--" {
-				// Permit running either:
+				// Permit running:
 				// $ go run run.go - env.go
 				// $ go run run.go -- env.go
+				// $ go run run.go - ./fixedbugs
+				// $ go run run.go -- ./fixedbugs
 				continue
 			}
-			if !strings.HasSuffix(arg, ".go") {
-				log.Fatalf("can't yet deal with non-go file %q", arg)
+			if fi, err := os.Stat(arg); err == nil && fi.IsDir() {
+				for _, baseGoFile := range goFiles(arg) {
+					tests = append(tests, startTest(arg, baseGoFile))
+				}
+			} else if strings.HasSuffix(arg, ".go") {
+				dir, file := filepath.Split(arg)
+				tests = append(tests, startTest(dir, file))
+			} else {
+				log.Fatalf("can't yet deal with non-directory and non-go file %q", arg)
 			}
-			dir, file := filepath.Split(arg)
-			tests = append(tests, startTest(dir, file))
 		}
 	} else {
 		for _, dir := range dirs {

src/run.bash の変更点

--- a/src/run.bash
+++ b/src/run.bash
@@ -49,12 +49,12 @@ xcd() {
 [ "$CGO_ENABLED" != 1 ] ||
 [ "$GOHOSTOS" == windows ] ||
 (xcd ../misc/cgo/stdio
-./test.bash
+go run $GOROOT/test/run.go - .
 ) || exit $?
 
 [ "$CGO_ENABLED" != 1 ] ||
 (xcd ../misc/cgo/life
-./test.bash
+go run $GOROOT/test/run.go - .
 ) || exit $?
 
 [ "$CGO_ENABLED" != 1 ] ||

src/run.bat の変更点

--- a/src/run.bat
+++ b/src/run.bat
@@ -30,6 +30,13 @@ echo.
 :: at least runtime/debug test will fail.
 set GOROOT_FINAL=\
 
+:: get CGO_ENABLED
+go env > env.bat
+if errorlevel 1 goto fail
+call env.bat
+del env.bat
+echo.
+
 echo # Testing packages.
 go test std -short -timeout=120s
 if errorlevel 1 goto fail
@@ -56,6 +63,15 @@ echo.\n
 ::if errorlevel 1 goto fail
 ::echo.\n
 
+:: cgo tests
+:: TODO: Other cgo tests
+if x%CGO_ENABLED% == x0 goto nocgo
+echo # ..\misc\cgo\life
+go run %GOROOT%\test\run.go - ..\misc\cgo\life
+if errorlevel 1 goto fail
+echo.\n
+:nocgo
+\n
 :: TODO: The other tests in run.bash.\n
 \n
 echo # test

コアとなるコードの解説

test/run.go の変更解説

この変更は、test/run.go がコマンドライン引数として受け取る対象を拡張し、より汎用的なテストランナーとしての役割を強化しています。

  • 引数処理の分岐: 以前は引数が .go ファイルであることのみを想定していましたが、if fi, err := os.Stat(arg); err == nil && fi.IsDir() という条件分岐が追加されました。
    • os.Stat(arg): 引数 arg のファイル情報を取得します。
    • fi.IsDir(): 取得したファイル情報がディレクトリであるかどうかを判定します。
  • ディレクトリ内のテスト実行: 引数がディレクトリであると判定された場合、for _, baseGoFile := range goFiles(arg) ループが実行されます。
    • goFiles(arg): この関数はコミット差分には含まれていませんが、指定されたディレクトリ arg 内にあるすべてのGoソースファイル(テスト対象となるファイル)のリストを返すものと推測されます。
    • ループ内で、検出された各Goファイルに対して startTest(arg, baseGoFile) が呼び出されます。これにより、ディレクトリ内の複数のテストが自動的に実行されるようになります。
  • 単一Goファイルのテスト実行: 引数が依然として単一の .go ファイルである場合は、else if strings.HasSuffix(arg, ".go") のブロックが実行され、以前と同様に filepath.Split でディレクトリとファイル名に分割し、startTest を呼び出します。
  • エラーハンドリングの強化: else { log.Fatalf("can't yet deal with non-directory and non-go file %q", arg) } が追加されました。これにより、.go ファイルでもディレクトリでもない不正な引数が渡された場合に、より明確なエラーメッセージを出力してプログラムを終了するようになりました。これは、テストランナーの堅牢性を高める変更です。

この変更により、test/run.go は、個別のGoテストファイルだけでなく、特定のディレクトリにまとめられたテストスイート全体を効率的に実行できる、より強力なツールとなりました。

src/run.bash および src/run.bat の変更解説

これらのシェルスクリプト(Unix系OS用とWindows用)は、Goプロジェクトの主要なテスト実行エントリポイントです。変更の目的は、CGOテストの実行方法を、個別の test.bash スクリプトから、Go言語製の test/run.go へと切り替えることです。

  • src/run.bash:
    • misc/cgo/stdio および misc/cgo/life ディレクトリでのテスト実行部分が、./test.bash の呼び出しから go run $GOROOT/test/run.go - . へと変更されました。
    • $GOROOT/test/run.go: Goのインストールディレクトリにある test/run.go を指定しています。
    • - .: test/run.go に渡される引数で、現在のディレクトリ(.)内のテストを実行するように指示しています。これは、test/run.go の機能拡張と連携しています。
  • src/run.bat:
    • Windows環境でのCGOテスト実行ロジックが追加されました。
    • go env > env.batcall env.bat を使って CGO_ENABLED 環境変数を取得しています。これは、CGOが有効になっている場合にのみCGOテストを実行するための条件分岐 (if x%CGO_ENABLED% == x0 goto nocgo) を可能にします。
    • go run %GOROOT%\test\run.go - ..\misc\cgo\life: misc/cgo/life ディレクトリのCGOテストを test/run.go を使って実行するように変更されています。コミットメッセージにある「Will enable stdio tests on Windows in a follow-up CL.」の通り、この時点では stdio テストは含まれていませんが、将来的な拡張を見越した基盤が作られています。

これらの変更により、Goプロジェクトのビルドおよびテストシステムは、CGOテストの実行において、より統一されたGo言語ベースのアプローチを採用するようになりました。これにより、テストの信頼性、保守性、そしてクロスプラットフォーム互換性が向上します。

関連リンク

参考にした情報源リンク

  • Go言語のソースコード (GitHub): https://github.com/golang/go
  • Gerrit Code Review (Goプロジェクト): https://go.dev/cl/ (コミットメッセージに記載されている https://golang.org/cl/6220049 は、このGerritインスタンス上の変更リストへのリンクです。)
  • Go言語のテストにおけるゴールデンファイル: (一般的な概念であり、特定の公式ドキュメントは少ないですが、Goコミュニティで広く使われているパターンです。)
    • 例: https://pkg.go.dev/cmd/go#hdr-Test_packages (直接的な言及はないが、テストの出力比較の文脈で理解される)
    • Goのテストに関するブログ記事やチュートリアルで言及されることが多い。