[インデックス 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
の出力からテストファイルに関連する行を除外するために使用されています。
strstr
と suffix
(C言語の文字列関数)
strstr(haystack, needle)
: C言語の標準ライブラリ関数で、haystack
文字列内にneedle
文字列が最初に現れる場所へのポインタを返します。見つからない場合はNULL
を返します。このコミット以前は、gobuild.c
でファイル名に"test.go"が含まれるかをチェックするために使用されていました。suffix(string, suffix_string)
: この関数は、Goの初期のC言語で書かれたツール(gobuild.c
)内で定義されたカスタム関数である可能性が高いです。その名前から、string
がsuffix_string
で終わるかどうかをチェックする目的で使用されていると推測されます。このコミットでは、より厳密な_test.go
サフィックスのチェックに置き換えられました。
技術的詳細
このコミットの主要な変更点は、Goのビルドシステムとテストカバレッジツールがテストファイルを識別する方法を、より厳密な命名規則*_test.go
に準拠させるように修正したことです。
-
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
で終わるファイルのみを対象とするように正規表現を修正したものです。
- 変更前:
-
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
サフィックスを持つファイルに限定されました。
- Goの標準ライブラリ内の複数のパッケージ(
-
テストファイルのファイル名変更:
src/lib/reflect/test.go
がsrc/lib/reflect/all_test.go
にリネームされました。src/lib/regexp/test.go
がsrc/lib/regexp/all_test.go
にリネームされました。- これらのリネームは、新しい
_test.go
命名規則に準拠するための具体的な対応です。reflect
パッケージのall_test.go
では、内部の文字列アサーションもファイル名変更に合わせて更新されています。
-
src/lib/net/Makefile
およびsrc/lib/os/Makefile
の追加変更:- これらのMakefileでは、オブジェクトファイル(
.O
)の結合順序や、AR
(アーカイバ)コマンドの引数リストが調整されています。これは、テストファイルの命名規則変更とは直接関係ない、独立したビルドプロセスの最適化または修正である可能性があります。例えば、net
パッケージではO4
という変数が削除され、net.a
のビルドプロセスが3ステップに簡略化されています。os
パッケージでは、os_env.$O
の順序が変更されています。これらの変更は、ビルドの依存関係や効率性に関連する可能性があります。
- これらのMakefileでは、オブジェクトファイル(
これらの変更全体として、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
命名規則に準拠させる点にあります。
-
gobuild.c
の変更:main
関数内のstrstr
からsuffix
への変更は、ファイル名のマッチングロジックを根本的に変えています。strstr(argv[i], "test.go")
は、ファイル名の中に"test.go"という文字列がどこかに含まれていればマッチします。例えば、mytest.go
やtestdata.go
のようなファイルもテストファイルとして誤って扱われる可能性がありました。suffix(argv[i], "_test.go")
は、ファイル名が厳密に_test.go
で終わる場合のみマッチします。これにより、my_package_test.go
のような正規のテストファイルのみが対象となり、誤認識が防がれます。これは、Goのテストフレームワークが採用する標準的な命名規則をビルドツール側で強制する重要なステップです。
grep -v
の正規表現の変更も同様の目的です。^.*test\\.go:
は、行のどこかに"test.go:"が含まれるものを除外していましたが、_test\\.go:
は、_test.go:
という文字列が正確に含まれる行のみを除外します。これは、6cov
が生成するカバレッジレポートから、テストコード自身のカバレッジ情報を除外する際に、より正確なフィルタリングを行うためです。テストコード自身のカバレッジは通常、関心の対象外であるため、これをレポートから除外することで、実際のアプリケーションコードのカバレッジに集中できます。
-
Makefile
群の変更:- 各ライブラリの
Makefile
におけるgrep -v
パターンの統一は、プロジェクト全体でテストカバレッジレポートの生成方法を一貫させるためのものです。これにより、どのパッケージのテストを実行しても、6cov
の出力からテストファイルが正しく除外され、クリーンなカバレッジデータが得られるようになります。これは、大規模なプロジェクトにおいてビルドとテストの信頼性を維持するために不可欠な標準化のプロセスです。
- 各ライブラリの
-
テストファイルのリネーム:
test.go
からall_test.go
へのリネームは、新しい命名規則_test.go
に準拠するための直接的な対応です。これにより、gobuild
やgo test
のようなツールがこれらのファイルをテストファイルとして正しく認識できるようになります。reflect
パッケージのall_test.go
内の文字列アサーションの更新は、テストコード自体がファイル名に依存するようなケースでの整合性を保つための細かな修正です。
これらの変更は、Go言語の初期段階におけるビルドシステムとテストインフラストラクチャの成熟を示すものであり、後のgo build
やgo test
コマンドの基盤となる堅牢なテストファイル識別メカニズムの確立に貢献しています。
関連リンク
- Go言語の公式ドキュメント(現在のテストに関する情報): https://go.dev/doc/code#Testing
- Go言語の初期のコミット履歴(GitHub): https://github.com/golang/go/commits/master
参考にした情報源リンク
- Go言語のコミット履歴 (GitHub): https://github.com/golang/go/commit/c0a01e966543dc1bdbbfe039c516098cc0e218cb
- Go言語の初期のビルドシステムに関する一般的な知識
- C言語の
strstr
関数に関する知識 - UNIXの
grep
コマンドに関する知識 Makefile
の一般的な構文と使用法に関する知識- Go言語のテストに関する一般的な知識
- (必要に応じて)
gobuild
や6cov
に関する当時の情報(ただし、このコミットの解析には直接的なWeb検索は不要でした)