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

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

このコミットは、Go言語の初期のビルドシステムであるgobuildにおけるテストファイルの識別方法を洗練し、命名規則を*_test.goに統一することを目的としています。具体的には、テストファイルが*test.goというパターンではなく、_test.goというサフィックスを持つファイルとして正確に認識されるように、ビルドツールと関連するMakefileの正規表現および文字列マッチングロジックが修正されています。これにより、テストファイルと非テストファイルの区別が明確になり、ビルドプロセスにおける潜在的な競合や誤認識が解消されます。

コミット

commit c0a01e966543dc1bdbbfe039c516098cc0e218cb
Author: Rob Pike <r@golang.org>
Date:   Wed Nov 19 19:43:32 2008 -0800

    refine gobuild: the files must be *_test.go not *test.go
    this causes complications
    
    R=rsc
    DELTA=1724  (849 added, 856 deleted, 19 changed)
    OCL=19667
    CL=19667

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

https://github.com/golang/go/commit/c0a01e966543dc1bdbbfe039c516098cc0e218cb

元コミット内容

refine gobuild: the files must be *_test.go not *test.go
this causes complications

R=rsc
DELTA=1724  (849 added, 856 deleted, 19 changed)
OCL=19667
CL=19667

変更の背景

Go言語の初期開発段階において、テストファイルの命名規則はまだ完全に確立されていませんでした。このコミット以前は、テストファイルが*test.goというパターンで識別されることがありました。しかし、この緩いパターンは、例えばmytest.goのような、テストコードではないがファイル名に"test.go"を含む通常のGoソースファイルと、実際のテストファイル(例: package_test.go)を区別する上で問題を引き起こす可能性がありました。

具体的には、gobuildツールやカバレッジツール(6cov)が、意図しないファイルをテストファイルとして扱ったり、カバレッジレポートから除外すべきでないファイルを誤って除外したりする「complications(複雑な問題)」が発生していました。このような曖昧さは、ビルドの正確性やテストカバレッジの信頼性を損なうため、テストファイルの命名規則をより厳密な*_test.go(アンダースコアで始まるtest.goサフィックス)に統一し、それに合わせてツール側の識別ロジックを修正する必要がありました。この変更により、Goのテストシステムにおける堅牢性と予測可能性が向上しました。

前提知識の解説

Go言語のテストファイル命名規則 (_test.go)

Go言語では、テストコードは通常、テスト対象のパッケージと同じディレクトリに配置され、ファイル名が_test.goで終わる必要があります(例: my_package_test.go)。この命名規則は、Goの標準テストツールであるgo testがテストファイルを自動的に発見し、実行するために不可欠です。このコミットは、この慣習が確立される初期段階での調整を示しています。

gobuild

gobuildは、Go言語の初期のビルドツールの一つです。現在のgo buildコマンドの前身にあたるもので、Goソースコードのコンパイル、リンク、テストの実行などを管理していました。このツールは、Goのモジュールシステムやパッケージ管理が成熟する以前の、よりシンプルなビルドプロセスを担っていました。

6cov

6covは、Go言語の初期のコードカバレッジツールです。現在のgo tool coverに相当する機能を提供していました。コンパイルされたGoプログラムの実行中に、どのコードが実行されたかを追跡し、カバレッジレポートを生成するために使用されました。このツールは、テストがコードのどの部分をカバーしているかを開発者が理解するのに役立ちました。

Makefile

Makefileは、ソフトウェアのビルドプロセスを自動化するためのファイルです。makeユーティリティによって解釈され、ソースコードのコンパイル、ライブラリのリンク、テストの実行など、一連のコマンドを定義します。Go言語の初期のプロジェクトでは、ビルドプロセスを管理するために広くMakefileが使用されていました。

grep -v

grepは、テキストファイルから正規表現にマッチする行を検索するUNIXコマンドです。-vオプションは、「マッチしない行」を表示するために使用されます。このコミットでは、6covの出力からテストファイルに関連する行を除外するために使用されています。

strstrsuffix (C言語の文字列関数)

  • strstr(haystack, needle): C言語の標準ライブラリ関数で、haystack文字列内にneedle文字列が最初に現れる場所へのポインタを返します。見つからない場合はNULLを返します。このコミット以前は、gobuild.cでファイル名に"test.go"が含まれるかをチェックするために使用されていました。
  • suffix(string, suffix_string): この関数は、Goの初期のC言語で書かれたツール(gobuild.c)内で定義されたカスタム関数である可能性が高いです。その名前から、stringsuffix_stringで終わるかどうかをチェックする目的で使用されていると推測されます。このコミットでは、より厳密な_test.goサフィックスのチェックに置き換えられました。

技術的詳細

このコミットの主要な変更点は、Goのビルドシステムとテストカバレッジツールがテストファイルを識別する方法を、より厳密な命名規則*_test.goに準拠させるように修正したことです。

  1. src/cmd/gobuild/gobuild.c の変更:

    • main関数内で、コマンドライン引数として渡されるファイル名がテストファイルであるかを判定するロジックが変更されました。
      • 変更前: if(strstr(argv[i], "test.go") != nil)
      • 変更後: if(suffix(argv[i], "_test.go") != nil)
      • これにより、ファイル名に単に"test.go"が含まれるだけでなく、_test.goで終わるファイルのみがテストファイルとして認識されるようになりました。
    • カバレッジレポート生成時のgrepパターンも変更されました。
      • 変更前: 6cov -g pwd | grep -v '^.*test\\.go:'
      • 変更後: 6cov -g pwd | grep -v '_test\\.go:'
      • これは、6covの出力からテストファイルに関連する行を除外する際に、_test.goで終わるファイルのみを対象とするように正規表現を修正したものです。
  2. src/lib/*/Makefile の変更:

    • Goの標準ライブラリ内の複数のパッケージ(container/array, fmt, http, math, net, os, reflect, regexp, strconv, syscall)のMakefileが修正されました。
    • これらのMakefileには、coverageターゲット内で6covコマンドの出力からテストファイルを除外するためのgrep -vコマンドが含まれていました。
    • 変更前は、'^.*test\\.go:''^test.*\\.go:'といった正規表現が使用されていましたが、これらがすべて'_test\\.go:'に統一されました。これにより、カバレッジレポートから除外されるテストファイルの基準が、_test.goサフィックスを持つファイルに限定されました。
  3. テストファイルのファイル名変更:

    • src/lib/reflect/test.gosrc/lib/reflect/all_test.go にリネームされました。
    • src/lib/regexp/test.gosrc/lib/regexp/all_test.go にリネームされました。
    • これらのリネームは、新しい_test.go命名規則に準拠するための具体的な対応です。reflectパッケージのall_test.goでは、内部の文字列アサーションもファイル名変更に合わせて更新されています。
  4. src/lib/net/Makefile および src/lib/os/Makefile の追加変更:

    • これらのMakefileでは、オブジェクトファイル(.O)の結合順序や、AR(アーカイバ)コマンドの引数リストが調整されています。これは、テストファイルの命名規則変更とは直接関係ない、独立したビルドプロセスの最適化または修正である可能性があります。例えば、netパッケージではO4という変数が削除され、net.aのビルドプロセスが3ステップに簡略化されています。osパッケージでは、os_env.$Oの順序が変更されています。これらの変更は、ビルドの依存関係や効率性に関連する可能性があります。

これらの変更全体として、Goのビルドシステムがテストファイルをより正確に識別し、テストカバレッジレポートが意図した通りに生成されるように、基盤となるロジックを強化しています。

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

src/cmd/gobuild/gobuild.c

--- a/src/cmd/gobuild/gobuild.c
+++ b/src/cmd/gobuild/gobuild.c
@@ -290,7 +290,7 @@ char preamble[] =
 	"\\n"
 	"coverage: packages\\n"
 	"	gotest\\n"
-	"	6cov -g `pwd` | grep -v '^.*test\\\\.go:'\\n"
+	"	6cov -g `pwd` | grep -v '_test\\\\.go:'\\n"
 	"\\n"
 	"%%.$O: %%.go\\n"
 	"	$(GC) $*.go\\n"
@@ -487,7 +487,7 @@ main(int argc, char **argv)
 	njob = 0;
 	job = emalloc(argc*sizeof job[0]);
 	for(i=0; i<argc; i++) {
-		if(strstr(argv[i], "test.go") != nil)
+		if(suffix(argv[i], "_test.go") != nil)
 			continue;
 		job[njob].name = argv[i];
 		job[njob].pass = -1;

src/lib/reflect/test.go から src/lib/reflect/all_test.go へのリネームと内容変更

--- a/src/lib/reflect/test.go
+++ b/src/lib/reflect/all_test.go
@@ -175,24 +175,24 @@ export func TestAll(tt *testing.T) {	// TODO(r): wrap up better
 		type C chan *T;	// TODO: should not be necessary
 		var tmp = new(C);
 		value := reflect.NewValue(tmp);
-		assert(reflect.ValueToString(value), "*reflect.C·test(@)");
+		assert(reflect.ValueToString(value), "*reflect.C·all_test(@)");
 	}
 	{
 		type A [10]int;
 		var tmp A = A{1,2,3,4,5,6,7,8,9,10};
 		value := reflect.NewValue(&tmp);
-		assert(reflect.ValueToString(value.(reflect.PtrValue).Sub()), "reflect.A·test{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}");
+		assert(reflect.ValueToString(value.(reflect.PtrValue).Sub()), "reflect.A·all_test{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}");
 		value.(reflect.PtrValue).Sub().(reflect.ArrayValue).Elem(4).(reflect.IntValue).Set(123);
-		assert(reflect.ValueToString(value.(reflect.PtrValue).Sub()), "reflect.A·test{1, 2, 3, 4, 123, 6, 7, 8, 9, 10}");
+		assert(reflect.ValueToString(value.(reflect.PtrValue).Sub()), "reflect.A·all_test{1, 2, 3, 4, 123, 6, 7, 8, 9, 10}");
 	}
 	{
 		type AA []int;
 		tmp1 := [10]int{1,2,3,4,5,6,7,8,9,10};	// TODO: should not be necessary to use tmp1
 		var tmp *AA = &tmp1;
 		value := reflect.NewValue(tmp);
-		assert(reflect.ValueToString(value.(reflect.PtrValue).Sub()), "reflect.AA·test{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}");
+		assert(reflect.ValueToString(value.(reflect.PtrValue).Sub()), "reflect.AA·all_test{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}");
 		value.(reflect.PtrValue).Sub().(reflect.ArrayValue).Elem(4).(reflect.IntValue).Set(123);
-		assert(reflect.ValueToString(value.(reflect.PtrValue).Sub()), "reflect.AA·test{1, 2, 3, 4, 123, 6, 7, 8, 9, 10}");
+		assert(reflect.ValueToString(value.(reflect.PtrValue).Sub()), "reflect.AA·all_test{1, 2, 3, 4, 123, 6, 7, 8, 9, 10}");
 	}

src/lib/regexp/test.go から src/lib/regexp/all_test.go へのリネーム

(内容は変更なし、ファイル名のみ変更)

複数の src/lib/*/Makefile における grep -v パターンの変更例 (src/lib/container/array/Makefile の例)

--- a/src/lib/container/array/Makefile
+++ b/src/lib/container/array/Makefile
@@ -20,7 +20,7 @@ test: packages
 
 coverage: packages
 	gotest
-\t6cov -g `pwd` | grep -v '^.*test\\.go:'\
+\t6cov -g `pwd` | grep -v '_test\\.go:'\
 
 %.$O: %.go
 	$(GC) $*.go

コアとなるコードの解説

このコミットの核心は、Goのビルドおよびテストカバレッジシステムが、テストファイルを識別する際の「曖昧さ」を排除し、より厳密な_test.go命名規則に準拠させる点にあります。

  1. gobuild.c の変更:

    • main関数内のstrstrからsuffixへの変更は、ファイル名のマッチングロジックを根本的に変えています。
      • strstr(argv[i], "test.go")は、ファイル名の中に"test.go"という文字列がどこかに含まれていればマッチします。例えば、mytest.gotestdata.goのようなファイルもテストファイルとして誤って扱われる可能性がありました。
      • suffix(argv[i], "_test.go")は、ファイル名が厳密に_test.goで終わる場合のみマッチします。これにより、my_package_test.goのような正規のテストファイルのみが対象となり、誤認識が防がれます。これは、Goのテストフレームワークが採用する標準的な命名規則をビルドツール側で強制する重要なステップです。
    • grep -vの正規表現の変更も同様の目的です。^.*test\\.go:は、行のどこかに"test.go:"が含まれるものを除外していましたが、_test\\.go:は、_test.go:という文字列が正確に含まれる行のみを除外します。これは、6covが生成するカバレッジレポートから、テストコード自身のカバレッジ情報を除外する際に、より正確なフィルタリングを行うためです。テストコード自身のカバレッジは通常、関心の対象外であるため、これをレポートから除外することで、実際のアプリケーションコードのカバレッジに集中できます。
  2. Makefile群の変更:

    • 各ライブラリのMakefileにおけるgrep -vパターンの統一は、プロジェクト全体でテストカバレッジレポートの生成方法を一貫させるためのものです。これにより、どのパッケージのテストを実行しても、6covの出力からテストファイルが正しく除外され、クリーンなカバレッジデータが得られるようになります。これは、大規模なプロジェクトにおいてビルドとテストの信頼性を維持するために不可欠な標準化のプロセスです。
  3. テストファイルのリネーム:

    • test.goからall_test.goへのリネームは、新しい命名規則_test.goに準拠するための直接的な対応です。これにより、gobuildgo testのようなツールがこれらのファイルをテストファイルとして正しく認識できるようになります。reflectパッケージのall_test.go内の文字列アサーションの更新は、テストコード自体がファイル名に依存するようなケースでの整合性を保つための細かな修正です。

これらの変更は、Go言語の初期段階におけるビルドシステムとテストインフラストラクチャの成熟を示すものであり、後のgo buildgo testコマンドの基盤となる堅牢なテストファイル識別メカニズムの確立に貢献しています。

関連リンク

参考にした情報源リンク

  • Go言語のコミット履歴 (GitHub): https://github.com/golang/go/commit/c0a01e966543dc1bdbbfe039c516098cc0e218cb
  • Go言語の初期のビルドシステムに関する一般的な知識
  • C言語のstrstr関数に関する知識
  • UNIXのgrepコマンドに関する知識
  • Makefileの一般的な構文と使用法に関する知識
  • Go言語のテストに関する一般的な知識
  • (必要に応じて)gobuild6covに関する当時の情報(ただし、このコミットの解析には直接的なWeb検索は不要でした)