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

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

このコミットは、Go言語のコマンドラインツールcmd/gotag_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.gogoinstallからコピー

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.r59weekly.2011-10-13)と、利用可能なGoのバージョンタグのリストを比較し、最も適切なものを選択するために使用されていました。

cmd/gogoinstallの機能を吸収する過程で、この重要なバージョン選択ロジックも移行する必要がありました。テストコードは、そのロジックが正しく機能することを保証するための重要な要素です。したがって、goinstallで既に存在し、機能が検証されていたtag_test.gocmd/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ソースコードやバイナリを識別し、ダウンロードするために重要でした。

goinstallcmd/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のバージョンタグを正しく選択できるかを検証します。

ファイルは以下の主要な要素で構成されています。

  1. package main: このテストファイルがcmd/goのメインパッケージの一部であることを示します。
  2. import "testing": Goの標準テストパッケージをインポートします。
  3. 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関数が正しいタグのみを識別し、無関係な文字列を無視できるかをテストします。
  4. selectTagTests変数:
    • var selectTagTests = []struct { version string; selected string }{...}として定義された構造体のスライスです。
    • これは、テーブルドリブンテストのテストケースを定義しています。各構造体は以下のフィールドを持ちます。
      • version: selectTag関数に渡される入力となるバージョン文字列(例: release.r59, weekly.2010-01-01, junkなど)。
      • selected: selectTag関数がversionselectTagTestTagsに基づいて返すことが期待される、正しい選択されたタグの文字列。期待される結果がない場合は空文字列""になります。
    • このテストケースのセットは、様々なシナリオ(正確なマッチ、より新しいリリースへのフォールバック、週次ビルドの選択、無効な入力の処理など)をカバーしています。
  5. 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の標準的なテストパターンであるテーブルドリブンテストを採用しています。

  1. selectTagTestTags: このグローバル変数は、selectTag関数が利用可能なGoのバージョンタグのリストをシミュレートするために使用されます。これには、正規のGoバージョンタグ(go.rXXgo.weekly.YYYY-MM-DD)と、selectTag関数が無視すべき不正な形式のタグや無関係な文字列が含まれています。これにより、selectTag関数が正確なフィルタリングと識別を行えるかを検証します。

  2. selectTagTests: このグローバル変数は、テストケースの集合を定義しています。各要素は匿名構造体であり、テストの入力(version)と期待される出力(selected)をペアで保持しています。

    • version: selectTag関数に渡される、ユーザーが指定する可能性のあるGoのバージョン文字列です。これには、リリースバージョン(release.r59)、週次ビルド(weekly.2011-10-12)、未来の日付、過去の日付、不正な形式の文字列などが含まれます。
    • selected: selectTag関数がversionselectTagTestTagsに基づいて返すことが期待される、最終的に選択されるGoのバージョンタグです。期待されるタグが見つからない場合は空文字列""となります。 このテストケースの網羅性は、selectTag関数が様々なエッジケースや一般的なシナリオで正しく動作することを保証するために重要です。例えば、release.r60が与えられたときに、利用可能なタグの中で最も近いgo.r59.1が選択されるといったフォールバックロジックもテストされています。
  3. 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言語のテストに関する公式ドキュメント: 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ブログ記事など)