[インデックス 12774] ファイルの概要
このコミットは、Go言語のコマンドラインツールcmd/go
にtag_test.go
という新しいテストファイルを追加するものです。このファイルは、以前goinstall
コマンドで使用されていたテストコードをcmd/go
にコピーしたものであり、Goのバージョンタグ(リリースバージョンや週次ビルドバージョン)の選択ロジックをテストすることを目的としています。
コミット
commit a3498f4be4844802c2a942dee3a61531e6ed5275
Author: Russ Cox <rsc@golang.org>
Date: Mon Mar 26 23:44:30 2012 -0400
cmd/go: copy tag_test.go from goinstall
hg cat -r 11846 src/cmd/goinstall/tag_test.go >tag_test.go
No changes.
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5919047
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/a3498f4be4844802c2a942dee3a61531e6ed5275
元コミット内容
cmd/go
: tag_test.go
をgoinstall
からコピー
hg cat -r 11846 src/cmd/goinstall/tag_test.go >tag_test.go
変更なし。
R=golang-dev, r CC=golang-dev https://golang.org/cl/5919047
変更の背景
このコミットが行われた2012年当時、Go言語のエコシステムはまだ発展途上にありました。goinstall
は、Goのパッケージをインストールするための初期のツールであり、Go 1のリリースに向けてcmd/go
(現在のgo
コマンド)にその機能が統合されつつありました。
goinstall
は、Goのソースコードリポジトリから特定のバージョンタグ(例: go.r58
, go.weekly.2011-10-12
など)に基づいて適切なGoのバージョンを選択するロジックを持っていました。このロジックは、ユーザーが指定したバージョン文字列(例: release.r59
やweekly.2011-10-13
)と、利用可能なGoのバージョンタグのリストを比較し、最も適切なものを選択するために使用されていました。
cmd/go
がgoinstall
の機能を吸収する過程で、この重要なバージョン選択ロジックも移行する必要がありました。テストコードは、そのロジックが正しく機能することを保証するための重要な要素です。したがって、goinstall
で既に存在し、機能が検証されていたtag_test.go
をcmd/go
にそのままコピーすることで、既存のテストカバレッジを維持し、新しいcmd/go
環境でもバージョン選択ロジックの正確性を保証することが目的でした。
コミットメッセージにあるhg cat -r 11846 src/cmd/goinstall/tag_test.go >tag_test.go
は、Mercurial(hg
)リビジョン11846のsrc/cmd/goinstall/tag_test.go
ファイルをそのままtag_test.go
としてコピーしたことを示しています。これは、コードの変更を伴わない、純粋なファイル移動/コピーであることを強調しています。
前提知識の解説
Go言語のバージョン管理とタグ
Go言語の公式リリースは、Go 1.x
のような形式でバージョン付けされています。しかし、このコミットが行われた初期の段階では、より細かいリビジョン番号(r58
など)や週次ビルド(weekly.YYYY-MM-DD
)といったタグが使われていました。
- リビジョンタグ (e.g.,
go.r58
,go.r59.1
): Goの初期開発段階で使われていた、特定の安定版や開発版を示すタグです。 - 週次ビルドタグ (e.g.,
go.weekly.2011-10-12
): 毎週生成される開発版のスナップショットを示すタグです。これらは、最新の開発状況を試したいユーザー向けに提供されていました。
これらのタグは、Goのツールが適切なバージョンのGoソースコードやバイナリを識別し、ダウンロードするために重要でした。
goinstall
とcmd/go
goinstall
: Go言語の初期のパッケージ管理ツールです。これは、Goのソースコードリポジトリからパッケージをフェッチし、ビルドしてインストールする機能を提供していました。Go 1のリリースに向けて、その機能はより包括的なgo
コマンド(cmd/go
)に統合されることになりました。cmd/go
: 現在のGo言語の主要なコマンドラインツールであるgo
コマンドの内部名です。このツールは、Goプログラムのビルド、テスト、実行、パッケージ管理など、Go開発のあらゆる側面をカバーしています。goinstall
の機能は、このcmd/go
の一部として取り込まれました。
Goのテストフレームワーク
Go言語には、標準ライブラリに組み込まれた軽量なテストフレームワークがあります。
testing
パッケージ: Goのテストコードを書くための主要なパッケージです。- テスト関数:
Test
で始まる関数名(例:TestSelectTag
)を持つ関数は、go test
コマンドによって自動的に実行されます。 *testing.T
: テスト関数に渡される引数で、テストの失敗を報告したり、ログを出力したりするためのメソッドを提供します。t.Errorf(...)
: テストが失敗したことを報告し、エラーメッセージを出力します。テストは続行されます。t.Fatalf(...)
: テストが失敗したことを報告し、エラーメッセージを出力した後、テストの実行を停止します。
- テーブルドリブンテスト: Goのテストでよく用いられるパターンで、テストケースを構造体のスライスとして定義し、ループで各テストケースを実行する手法です。これにより、テストコードの重複を減らし、可読性を高めることができます。
技術的詳細
このコミットで追加されたtag_test.go
ファイルは、selectTag
という(このテストファイルには含まれていないが、cmd/go
の他の場所で定義されているはずの)関数が、与えられたバージョン文字列と利用可能なタグのリストから、最も適切なGoのバージョンタグを正しく選択できるかを検証します。
ファイルは以下の主要な要素で構成されています。
package main
: このテストファイルがcmd/go
のメインパッケージの一部であることを示します。import "testing"
: Goの標準テストパッケージをインポートします。selectTagTestTags
変数:var selectTagTestTags = []string{...}
として定義された文字列スライスです。- これは、
selectTag
関数が利用可能なGoのバージョンタグの「データベース」として使用する、模擬的なタグのリストです。 - リストには、有効なGoのリリースタグ(
go.r58
,go.r59
など)、週次ビルドタグ(go.weekly.2011-10-12
など)のほか、無視されるべき無効な形式のタグ(release.r59
,weekly.2011-10-12
,foo
,go.f00
など)が含まれています。これにより、selectTag
関数が正しいタグのみを識別し、無関係な文字列を無視できるかをテストします。
selectTagTests
変数:var selectTagTests = []struct { version string; selected string }{...}
として定義された構造体のスライスです。- これは、テーブルドリブンテストのテストケースを定義しています。各構造体は以下のフィールドを持ちます。
version
:selectTag
関数に渡される入力となるバージョン文字列(例:release.r59
,weekly.2010-01-01
,junk
など)。selected
:selectTag
関数がversion
とselectTagTestTags
に基づいて返すことが期待される、正しい選択されたタグの文字列。期待される結果がない場合は空文字列""
になります。
- このテストケースのセットは、様々なシナリオ(正確なマッチ、より新しいリリースへのフォールバック、週次ビルドの選択、無効な入力の処理など)をカバーしています。
TestSelectTag
関数:func TestSelectTag(t *testing.T)
というシグネチャを持つGoのテスト関数です。- この関数は、
selectTagTests
スライスをループし、各テストケースに対して以下の処理を行います。selectTag(c.version, selectTagTestTags)
を呼び出し、実際のselectTag
関数の戻り値を取得します。- 取得した
selected
値が、テストケースで期待されるc.selected
値と一致するかを比較します。 - 一致しない場合、
t.Errorf(...)
を呼び出してテストの失敗を報告します。エラーメッセージには、入力バージョン、実際の戻り値、期待される戻り値が含まれ、デバッグに役立ちます。
このテストの目的は、selectTag
関数がGoのバージョンタグを正確に解析し、適切な優先順位付け(例: リリースバージョンが週次ビルドより優先される、より新しいリビジョンが選択されるなど)に基づいて選択できることを保証することです。
コアとなるコードの変更箇所
このコミットによる変更は、単一のファイルの追加です。
--- a/src/cmd/go/tag_test.go
+++ b/src/cmd/go/tag_test.go
@@ -0,0 +1,73 @@
+// Copyright 2011 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.
+
+package main
+
+import "testing"
+
+var selectTagTestTags = []string{
+ "go.r58",
+ "go.r58.1",
+ "go.r59",
+ "go.r59.1",
+ "go.r61",
+ "go.r61.1",
+ "go.weekly.2010-01-02",
+ "go.weekly.2011-10-12",
+ "go.weekly.2011-10-12.1",
+ "go.weekly.2011-10-14",
+ "go.weekly.2011-11-01",
+ // these should be ignored:
+ "release.r59",
+ "release.r59.1",
+ "release",
+ "weekly.2011-10-12",
+ "weekly.2011-10-12.1",
+ "weekly",
+ "foo",
+ "bar",
+ "go.f00",
+ "go!r60",
+ "go.1999-01-01",
+}
+
+var selectTagTests = []struct {
+ version string
+ selected string
+}{
+ {"release.r57", ""},
+ {"release.r58.2", "go.r58.1"},
+ {"release.r59", "go.r59"},
+ {"release.r59.1", "go.r59.1"},
+ {"release.r60", "go.r59.1"},
+ {"release.r60.1", "go.r59.1"},
+ {"release.r61", "go.r61"},
+ {"release.r66", "go.r61.1"},
+ {"weekly.2010-01-01", ""},
+ {"weekly.2010-01-02", "go.weekly.2010-01-02"},
+ {"weekly.2010-01-02.1", "go.weekly.2010-01-02"},
+ {"weekly.2010-01-03", "go.weekly.2010-01-02"},
+ {"weekly.2011-10-12", "go.weekly.2011-10-12"},
+ {"weekly.2011-10-12.1", "go.weekly.2011-10-12.1"},
+ {"weekly.2011-10-13", "go.weekly.2011-10-12.1"},
+ {"weekly.2011-10-14", "go.weekly.2011-10-14"},
+ {"weekly.2011-10-14.1", "go.weekly.2011-10-14"},
+ {"weekly.2011-11-01", "go.weekly.2011-11-01"},
+ {"weekly.2014-01-01", "go.weekly.2011-11-01"},
+ {"weekly.3000-01-01", "go.weekly.2011-11-01"},
+ // faulty versions:
+ {"release.f00", ""},
+ {"weekly.1999-01-01", ""},
+ {"junk", ""},
+ {"", ""},
+}
+
+func TestSelectTag(t *testing.T) {
+ for _, c := range selectTagTests {
+ selected := selectTag(c.version, selectTagTestTags)
+ if selected != c.selected {
+ t.Errorf("selectTag(%q) = %q, want %q", c.version, selected, c.selected)
+ }
+ }
+}
コアとなるコードの解説
追加されたtag_test.go
ファイルは、Goの標準的なテストパターンであるテーブルドリブンテストを採用しています。
-
selectTagTestTags
: このグローバル変数は、selectTag
関数が利用可能なGoのバージョンタグのリストをシミュレートするために使用されます。これには、正規のGoバージョンタグ(go.rXX
、go.weekly.YYYY-MM-DD
)と、selectTag
関数が無視すべき不正な形式のタグや無関係な文字列が含まれています。これにより、selectTag
関数が正確なフィルタリングと識別を行えるかを検証します。 -
selectTagTests
: このグローバル変数は、テストケースの集合を定義しています。各要素は匿名構造体であり、テストの入力(version
)と期待される出力(selected
)をペアで保持しています。version
:selectTag
関数に渡される、ユーザーが指定する可能性のあるGoのバージョン文字列です。これには、リリースバージョン(release.r59
)、週次ビルド(weekly.2011-10-12
)、未来の日付、過去の日付、不正な形式の文字列などが含まれます。selected
:selectTag
関数がversion
とselectTagTestTags
に基づいて返すことが期待される、最終的に選択されるGoのバージョンタグです。期待されるタグが見つからない場合は空文字列""
となります。 このテストケースの網羅性は、selectTag
関数が様々なエッジケースや一般的なシナリオで正しく動作することを保証するために重要です。例えば、release.r60
が与えられたときに、利用可能なタグの中で最も近いgo.r59.1
が選択されるといったフォールバックロジックもテストされています。
-
TestSelectTag
関数: これはGoのテスト関数であり、go test
コマンドによって自動的に実行されます。for _, c := range selectTagTests
:selectTagTests
スライスをイテレートし、各テストケースc
を取り出します。selected := selectTag(c.version, selectTagTestTags)
: 実際のテスト対象であるselectTag
関数を呼び出します。この関数は、c.version
(テスト入力)とselectTagTestTags
(利用可能なタグのリスト)を引数として受け取ります。if selected != c.selected
:selectTag
関数が返したselected
値が、テストケースで定義された期待値c.selected
と異なる場合、テストは失敗と判断されます。t.Errorf("selectTag(%q) = %q, want %q", c.version, selected, c.selected)
: テストが失敗した場合、t.Errorf
を呼び出してエラーメッセージを出力します。このメッセージは、どの入力で、どのような結果が得られ、どのような結果が期待されていたかを明確に示し、デバッグを容易にします。
このテストファイルは、selectTag
関数がGoのバージョンタグの複雑な選択ロジックを正確に処理できることを、多様な入力と期待される出力の組み合わせを通じて検証する、堅牢なテストスイートを提供しています。
関連リンク
- Go CL 5919047: https://golang.org/cl/5919047
参考にした情報源リンク
- Go言語のテストに関する公式ドキュメント: https://go.dev/doc/tutorial/add-a-test
- Go言語の初期のバージョン管理と
goinstall
に関する情報(当時のメーリングリストやブログ記事など、具体的なURLは特定が困難なため一般的な情報源として記載) - Mercurial (hg) コマンドに関する情報: https://www.mercurial-scm.org/
- Go言語のリリース履歴: https://go.dev/doc/devel/release
- Go言語の週次ビルドに関する情報(過去のGoブログ記事など)