[インデックス 18436] ファイルの概要
このコミットは、Go言語のコマンドラインツールcmd/go
のテストスクリプトtest.bash
における3つの既存のテストの不具合を修正し、さらにfoldDup
関数のテストを追加するものです。test.bash
は、go
コマンドの様々な挙動を検証するための統合テストスクリプトであり、これらの修正はgo
コマンドの堅牢性と正確性を保証するために重要です。
コミット
commit 414b45d91a3bcb5dacd5061c9a93cb8936592b87
Author: Dave Cheney <dave@cheney.net>
Date: Mon Feb 10 10:41:47 2014 +1100
cmd/go: fix test.bash
Fixes #7260.
Fix three broken tests in test.bash
The test for issue 4568 was confused by go $ACTION . producing a package root of "", avoiding this mode fixes the test but weakens the test.
The test for issue 4773 was broken on linux because math/Rand would fail to resolve as a package causing the test for duplicates to be skipped.
Finally, the last breakage was a small change in the error message.
Also, add test for foldDup.
LGTM=iant
R=iant, rsc
CC=golang-codereviews
https://golang.org/cl/61070044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/414b45d91a3bcb5dacd5061c9a93cb8936592b87
元コミット内容
このコミットは、cmd/go
ディレクトリ内のtest.bash
スクリプトにおける既存のテストの失敗を修正し、pkg_test.go
という新しいテストファイルを追加してfoldDup
関数のテストを導入します。具体的には、以下の3つの問題に対処しています。
- Issue 4568に関連するテストの修正:
go list .
がシンボリックリンクされたディレクトリ内で実行された際に、パッケージのルートが空文字列として誤って解釈される問題を修正します。この修正はテストを通過させますが、特定のケースでのテストの網羅性を若干低下させる可能性があります。 - Issue 4773に関連するテストの修正: Linux環境で
math/Rand
パッケージが解決できず、重複パッケージの検出テストがスキップされてしまう問題を修正します。これは、ファイルシステムの大文字・小文字の区別に関する問題に起因する可能性があります。修正では、テスト対象をローカルに作成した大文字・小文字が異なるパッケージ名に変更することで、この問題を回避しています。 - エラーメッセージの変更:
go install
コマンドのエラーメッセージの文字列がわずかに変更され、より一貫性のある形式になります。
さらに、foldDup
という内部関数のテストが追加され、パッケージパスの重複を処理するロジックの正確性が保証されます。
変更の背景
このコミットの主な背景は、Go言語のビルドシステムとツールチェーンの安定性を確保することです。cmd/go
はGo開発者が日常的に使用する中心的なツールであり、その動作は正確かつ予測可能である必要があります。テストの失敗は、ツールのバグを示唆するか、またはテスト自体が環境の変化に対応できていないことを意味します。
具体的には、以下の問題が背景にあります。
- テストの信頼性:
test.bash
はGoツールの動作を検証する重要な統合テストスイートです。テストが失敗すると、開発者はツールの変更が意図しない副作用を引き起こしていないか、または既存の機能が壊れていないかを判断できません。このコミットは、これらのテストを修正することで、テストスイートの信頼性を回復します。 - クロスプラットフォーム互換性: Issue 4773の修正は、特にLinux環境でのテストの失敗に対処しています。これは、異なるオペレーティングシステム(特にファイルシステムの大文字・小文字の区別)がGoツールの動作に与える影響を考慮する必要があることを示しています。
math/Rand
のような標準ライブラリのパッケージ名が、一部の環境で大文字・小文字の違いによって解決できないという問題は、クロスプラットフォーム開発における一般的な課題です。 go
コマンドの堅牢性:go list
やgo install
のようなコマンドは、パッケージの解決、ビルドパスの決定、エラー報告において堅牢である必要があります。このコミットは、これらのコマンドが特定のコーナーケース(例: シンボリックリンク、重複するパッケージ名)で正しく動作するように、基盤となるロジックとテストを改善します。- 内部関数のテストカバレッジ:
foldDup
のような内部ヘルパー関数のテストを追加することは、コードの品質と保守性を向上させます。これにより、将来の変更がこの重要なロジックを誤って破壊するリスクが低減します。
これらの修正は、Goツールの安定した開発と、開発者への信頼性の高いエクスペリエンスを提供するために不可欠です。
前提知識の解説
このコミットを理解するためには、以下のGo言語および関連技術の知識が役立ちます。
1. Go言語のパッケージシステム
Go言語のコードは「パッケージ」として組織されます。各Goファイルはpackage <name>
という宣言で始まり、関連する機能がまとめられます。パッケージはファイルシステム上のディレクトリ構造に対応しており、GOPATH
環境変数によって定義されるワークスペース内で管理されます。
GOPATH
: Goのソースコード、コンパイル済みバイナリ、パッケージが配置されるワークスペースのルートディレクトリです。通常、$GOPATH/src
にソースコードが、$GOPATH/pkg
にコンパイル済みパッケージが、$GOPATH/bin
にコンパイル済みコマンドが格納されます。- パッケージパス:
import
文で使用される文字列(例:"fmt"
,"github.com/user/repo/pkg"
)で、パッケージを一意に識別します。これは通常、GOPATH/src
からの相対パスに対応します。
2. go
コマンド
go
コマンドは、Go言語のソースコードを管理、ビルド、テスト、実行するための主要なツールです。
go list
: 指定されたパッケージに関する情報を表示します。例えば、go list -f '{{.Root}}' .
は現在のディレクトリのパッケージのルートディレクトリを表示します。go install
: パッケージをコンパイルし、その結果のバイナリまたはアーカイブをGOPATH
内の適切な場所にインストールします。go test
: パッケージのテストを実行します。
3. test.bash
スクリプト
Goプロジェクトでは、test.bash
のようなシェルスクリプトが、Goツールチェーン自体の統合テストや、特定の環境での挙動を検証するために広く使用されます。これらのスクリプトは、go
コマンドを様々な引数や環境変数で実行し、その出力や終了コードを検証することで、ツールの正確性を確認します。
4. シンボリックリンク
シンボリックリンク(またはソフトリンク)は、ファイルシステム内の別のファイルやディレクトリへの参照です。Goツールがシンボリックリンクをどのように扱うかは、パッケージの解決やパスの正規化において重要な考慮事項となります。
5. ファイルシステムの大文字・小文字の区別
オペレーティングシステムによって、ファイルシステムは大文字・小文字を区別する場合(例: Linux、macOSのデフォルト)と、区別しない場合(例: Windows、macOSのHFS+)があります。Goのパッケージシステムは、ファイルシステム上のパスに基づいてパッケージを解決するため、この違いが問題を引き起こすことがあります。例えば、math/rand
とmath/Rand
は、大文字・小文字を区別しないファイルシステムでは同じパスと見なされますが、区別するファイルシステムでは異なるパスと見なされます。
6. foldDup
関数(推測)
コミットメッセージとpkg_test.go
の追加から推測すると、foldDup
関数は、Goの内部でパッケージパスのリストを処理し、重複するパスや、大文字・小文字の違いによって実質的に同じパスと見なされるものを特定するためのヘルパー関数であると考えられます。これは、go
コマンドがパッケージの解決やビルドパスの決定を行う際に、重複や競合を検出するために使用される可能性があります。
技術的詳細
このコミットは、cmd/go
のテストスクリプトtest.bash
と、新しく追加されたsrc/cmd/go/pkg_test.go
ファイルにわたる具体的な変更を含んでいます。
1. src/cmd/go/pkg_test.go
の追加とfoldDup
テスト
このファイルは、foldDup
というGoの内部関数の単体テストを提供します。
-
foldDupTests
構造体:var foldDupTests = []struct { list []string f1, f2 string }{ {stringList("math/rand", "math/big"), "", ""}, {stringList("math", "strings"), "", ""}, {stringList("strings"), "", ""}, {stringList("strings", "strings"), "strings", "strings"}, {stringList("Rand", "rand", "math", "math/rand", "math/Rand"), "Rand", "rand"}, }
このテストデータは、
foldDup
関数に与えられる文字列のリスト(list
)と、期待される重複する要素(f1
,f2
)のペアを定義しています。 特に注目すべきは、最後のテストケースです。{"Rand", "rand", "math", "math/rand", "math/Rand"}
というリストに対して、期待される重複が"Rand"
と"rand"
となっています。これは、foldDup
関数がパッケージパスの大文字・小文字の違いを考慮して重複を検出することを示唆しています。Goのパッケージシステムは通常、パスの大文字・小文字を区別しますが、一部のファイルシステムでは区別しないため、このような「論理的な重複」を検出する必要がある場合があります。 -
TestFoldDup
関数:func TestFoldDup(t *testing.T) { for _, tt := range foldDupTests { f1, f2 := foldDup(tt.list) if f1 != tt.f1 || f2 != tt.f2 { t.Errorf("foldDup(%q) = %q, %q, want %q, %q", tt.list, f1, f2, tt.f1, tt.f2) } } }
このテスト関数は、
foldDupTests
の各テストケースをループし、foldDup
関数を呼び出してその結果を期待値と比較します。これにより、foldDup
が様々な入力に対して正しく重複を識別できることが保証されます。
2. src/cmd/go/test.bash
の修正
test.bash
スクリプト内の3つのテストが修正されています。
-
Issue 4568のテスト修正:
- 問題: 元のテストでは、シンボリックリンクされたディレクトリ(
$d/src/dir1
)にcd
してからgo list -f '{{.Root}}' .
を実行していました。この場合、go list
が現在のディレクトリ(.
)を評価する際に、パッケージのルートを空文字列として誤って解釈し、テストが失敗していました。これは、go
コマンドがシンボリックリンクと現在の作業ディレクトリの組み合わせを処理する際の特定のコーナーケースでの挙動の混乱を示しています。 - 修正:
cd $d/src
に移動し、go list -f '{{.Root}}' dir1
と明示的にパッケージパスを指定するように変更されました。これにより、go list
はdir1
という明確なパッケージパスを評価するため、正しいルートパス($d
)を返します。 - 影響: コミットメッセージには「weakens the test(テストを弱める)」と記載されています。これは、元のテストが
go list .
の特定の誤った挙動を捉えようとしていたのに対し、修正後はその特定のコーナーケースを直接テストしなくなったためと考えられます。しかし、テストの失敗を回避し、CI/CDパイプラインの健全性を維持するためには必要な妥協でした。
- 問題: 元のテストでは、シンボリックリンクされたディレクトリ(
-
Issue 4773のテスト修正:
- 問題: 元のテストでは、
import (_ "math/rand"; _ "math/Rand")
というコードを使用して、大文字・小文字が異なるが実質的に同じパッケージ名(ファイルシステムによっては)の重複を検出することを意図していました。しかし、Linux環境ではmath/Rand
というパッケージが存在しないため、このインポートが解決できず、テストが意図した重複検出ロジックに到達する前に失敗していました。これは、Goの標準ライブラリにはmath/Rand
という名前のパッケージは存在せず、math/rand
のみが存在するためです。テストの意図は、ファイルシステムが大文字・小文字を区別しない環境(例: Windows)で、math/rand
とmath/Rand
が同じファイルとして扱われる場合に、go
コマンドがその重複を正しく報告するかどうかを検証することでした。 - 修正: テストは、
example/a/pkg
とexample/a/Pkg
というローカルに作成されたパッケージをインポートするように変更されました。これらのパッケージは、それぞれ$d/src/example/a/pkg/pkg.go
と$d/src/example/a/Pkg/pkg.go
として明示的に作成されます。これにより、テストは標準ライブラリの存在に依存せず、ファイルシステムの大文字・小文字の区別に関わらず、意図した重複検出のシナリオを確実に再現できるようになります。
- 問題: 元のテストでは、
-
エラーメッセージの変更:
- 問題:
go install
コマンドがシャドウイングされた(隠された)インストールパスを報告する際のエラーメッセージのフォーマットが、他のエラーメッセージと一貫性がなかったか、またはより明確にする必要がありました。 - 修正: エラーメッセージの文字列が
"go install: no install location for directory $(pwd)/testdata/shadow/root2/src/foo hidden by $(pwd)/testdata/shadow/root1/src/foo"
から"go install: no install location for $(pwd)/testdata/shadow/root2/src/foo: hidden by $(pwd)/testdata/shadow/root1/src/foo"
に変更されました。具体的には、「directory」という単語が削除され、隠されたパスを示す部分の前にコロン(:
)が追加されました。これは、エラーメッセージの統一性と可読性を向上させるための小さな調整です。
- 問題:
これらの変更は、Goツールのテストスイートの信頼性を高め、異なる環境での一貫した動作を保証し、ユーザーへのエラー報告を改善することを目的としています。
コアとなるコードの変更箇所
このコミットにおけるコアとなるコードの変更箇所は以下の2つのファイルです。
-
src/cmd/go/pkg_test.go
:- このファイルは新規追加されました。
foldDupTests
というテストデータ構造体が定義されています。TestFoldDup
というテスト関数が定義されており、foldDup
という(このコミットでは定義されていないが、cmd/go
の他の場所で定義されていると推測される)関数をテストしています。このテストは、与えられた文字列リストの中から重複する要素を正しく識別できるかを検証します。特に、大文字・小文字の違いを考慮した重複検出のテストケースが含まれています。
-
src/cmd/go/test.bash
:- Issue 4568の修正:
--- a/src/cmd/go/test.bash +++ b/src/cmd/go/test.bash @@ -427,10 +427,10 @@ d=$(TMPDIR=$tmp mktemp -d -t testgoXXX)\n mkdir -p $d/src\n (\n ln -s $d $d/src/dir1\n- cd $d/src/dir1\n- echo package p >p.go\n+ cd $d/src\n+ echo package p >dir1/p.go\n export GOPATH=$d\n- if [ "$($old/testgo list -f '{{.Root}}' .)" != "$d" ]; then\n+ if [ "$($old/testgo list -f '{{.Root}}' dir1)" != "$d" ]; then\n echo Confused by symlinks.\n echo "Package in current directory $(pwd) should have Root $d"\n env|grep WD
cd
コマンドの対象ディレクトリとgo list
の引数が変更されています。 - Issue 4773の修正:
--- a/src/cmd/go/test.bash +++ b/src/cmd/go/test.bash @@ -479,14 +479,20 @@ rm -rf $d\n TEST case collisions '(issue 4773)'\n d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)\n export GOPATH=$d\n-mkdir -p $d/src/example/a $d/src/example/b\n+mkdir -p $d/src/example/{a/pkg,a/Pkg,b}\n cat >$d/src/example/a/a.go <<EOF\n package p\n import (\n-\t_ "math/rand"\n-\t_ "math/Rand"\n+\t_ "example/a/pkg"\n+\t_ "example/a/Pkg"\n )\n EOF\n+cat >$d/src/example/a/pkg/pkg.go <<EOF\n+package pkg\n+EOF\n+cat >$d/src/example/a/Pkg/pkg.go <<EOF\n+package pkg\n+EOF\n if ./testgo list example/a 2>$d/out; then\n echo go list example/a should have failed, did not.\n ok=false
mkdir -p
の引数、インポートパス、および新しいパッケージファイルの作成が追加されています。 - エラーメッセージの修正:
エラーメッセージの期待値文字列が変更されています。--- a/src/cmd/go/test.bash +++ b/src/cmd/go/test.bash @@ -547,7 +553,7 @@ fi\n \n # The error for go install should mention the conflicting directory.\n err=$(! ./testgo install ./testdata/shadow/root2/src/foo 2>&1)\n-if [ "$err" != "go install: no install location for directory $(pwd)/testdata/shadow/root2/src/foo hidden by $(pwd)/testdata/shadow/root1/src/foo" ]; then\n+if [ "$err" != "go install: no install location for $(pwd)/testdata/shadow/root2/src/foo: hidden by $(pwd)/testdata/shadow/root1/src/foo" ]; then\n echo wrong shadowed install error: "$err"\n ok=false\n fi
- Issue 4568の修正:
コアとなるコードの解説
src/cmd/go/pkg_test.go
のTestFoldDup
この新しいテストファイルは、cmd/go
内部で使用されるであろうfoldDup
という関数の正確性を検証します。foldDup
は、Goのパッケージパスのリストを受け取り、その中に重複する要素がないか、あるいは大文字・小文字の違いによって実質的に同じと見なされる要素がないかを検出する役割を担っていると推測されます。
例えば、{"Rand", "rand", "math", "math/rand", "math/Rand"}
というテストケースでは、"Rand"
と"rand"
が重複として検出されることを期待しています。これは、Goのパッケージシステムが通常はパスの大文字・小文字を区別する一方で、Windowsのような大文字・小文字を区別しないファイルシステム上ではmath/rand
とmath/Rand
が同じディレクトリを指す可能性があるため、このような「論理的な重複」を検出する必要があることを示唆しています。foldDup
関数は、このような状況でgo
コマンドが混乱しないように、重複するパスを適切に処理するための内部ロジックの一部であると考えられます。このテストの追加により、foldDup
のロジックが堅牢であり、将来の変更によって誤って破壊されることがないように保証されます。
src/cmd/go/test.bash
の修正
-
Issue 4568のテスト修正: この修正は、
go list .
がシンボリックリンクされたディレクトリ内で実行された際のgo
コマンドの挙動に関するものです。元のテストでは、$d/src/dir1
というシンボリックリンクされたディレクトリにcd
してからgo list .
を実行していました。この状況でgo list
がパッケージのルートを正しく識別できず、空文字列を返していたためテストが失敗していました。 修正では、cd $d/src
(シンボリックリンクの親ディレクトリ)に移動し、go list dir1
と明示的にパッケージパスを指定するように変更されました。これにより、go list
はdir1
という明確なパスを評価し、正しいルートパス($d
)を返すようになります。 コミットメッセージにある「weakens the test」という記述は、この修正がgo list .
がシンボリックリンクされたディレクトリ内でどのように振る舞うかという特定のコーナーケースを直接テストしなくなったことを意味します。しかし、テストの失敗を回避し、CI/CDパイプラインの健全性を維持するためには、この変更が必要でした。 -
Issue 4773のテスト修正: この修正は、Goのパッケージシステムがファイルシステムの大文字・小文字の区別をどのように扱うかに関連するテストの信頼性を向上させます。元のテストは、
math/rand
とmath/Rand
というインポートを使用して、大文字・小文字が異なるパッケージ名の重複を検出することを意図していました。しかし、Linuxのような大文字・小文字を区別するファイルシステムではmath/Rand
というパッケージが存在しないため、インポートが失敗し、テストが意図した重複検出ロジックに到達する前に中断していました。 修正では、テストは標準ライブラリに依存する代わりに、example/a/pkg
とexample/a/Pkg
というローカルに作成されたパッケージを使用するように変更されました。これらのパッケージは、それぞれpkg.go
ファイルを持つ異なるディレクトリに配置され、大文字・小文字のみが異なります。これにより、テストはファイルシステムの大文字・小文字の区別に関わらず、意図した重複検出のシナリオを確実に再現できるようになります。これは、テストがより自己完結型になり、外部環境(この場合は標準ライブラリの特定のパッケージの存在)に依存しなくなるため、テストの堅牢性が向上します。 -
エラーメッセージの修正: これは比較的小さな変更ですが、
go install
コマンドがシャドウイングされたインストールパスを報告する際のエラーメッセージのフォーマットを調整するものです。元のメッセージは「no install location for directory ... hidden by ...」という形式でしたが、修正後は「no install location for ...: hidden by ...」という形式になります。 この変更は、エラーメッセージの統一性を高め、Goツールの全体的なユーザーエクスペリエンスを向上させることを目的としています。一貫性のあるエラーメッセージは、ユーザーが問題を診断し、解決するのに役立ちます。
これらの変更は、Goツールのテストスイートの信頼性を高め、異なる環境での一貫した動作を保証し、ユーザーへのエラー報告を改善することで、Go開発エコシステムの健全性に貢献しています。
関連リンク
- Go Issue 7260: https://github.com/golang/go/issues/7260
- Go Issue 4568: https://github.com/golang/go/issues/4568
- Go Issue 4773: https://github.com/golang/go/issues/4773
- Gerrit Change-Id:
61070044
(GoのコードレビューシステムGerritの変更ID)
参考にした情報源リンク
- Go言語公式ドキュメント: https://go.dev/doc/
- Go Modules Reference: https://go.dev/ref/mod
go
コマンドのドキュメント: https://go.dev/cmd/go/- Goのテストに関するドキュメント: https://go.dev/doc/code#testing
- GoのGOPATHに関するドキュメント: https://go.dev/doc/gopath_code
- Goのコードレビュープロセス (Gerrit): https://go.dev/doc/contribute#code_reviews
- ファイルシステムの大文字・小文字の区別に関する一般的な情報 (Wikipediaなど)
- シンボリックリンクに関する一般的な情報 (Wikipediaなど)
- Goのソースコード (特に
cmd/go
ディレクトリ): https://github.com/golang/go/tree/master/src/cmd/go - Dave Cheneyのブログ (Goに関する技術記事): https://dave.cheney.net/ (コミット著者)
- Ian Lance Taylor (iant) の情報 (Goの貢献者): https://research.swtch.com/ (LGTM, R)
- Russ Cox (rsc) の情報 (Goの貢献者): https://research.swtch.com/ (R)
- golang-codereviewsメーリングリスト: https://groups.google.com/g/golang-codereviews (CC)