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

[インデックス 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つの問題に対処しています。

  1. Issue 4568に関連するテストの修正: go list .がシンボリックリンクされたディレクトリ内で実行された際に、パッケージのルートが空文字列として誤って解釈される問題を修正します。この修正はテストを通過させますが、特定のケースでのテストの網羅性を若干低下させる可能性があります。
  2. Issue 4773に関連するテストの修正: Linux環境でmath/Randパッケージが解決できず、重複パッケージの検出テストがスキップされてしまう問題を修正します。これは、ファイルシステムの大文字・小文字の区別に関する問題に起因する可能性があります。修正では、テスト対象をローカルに作成した大文字・小文字が異なるパッケージ名に変更することで、この問題を回避しています。
  3. エラーメッセージの変更: go installコマンドのエラーメッセージの文字列がわずかに変更され、より一貫性のある形式になります。

さらに、foldDupという内部関数のテストが追加され、パッケージパスの重複を処理するロジックの正確性が保証されます。

変更の背景

このコミットの主な背景は、Go言語のビルドシステムとツールチェーンの安定性を確保することです。cmd/goはGo開発者が日常的に使用する中心的なツールであり、その動作は正確かつ予測可能である必要があります。テストの失敗は、ツールのバグを示唆するか、またはテスト自体が環境の変化に対応できていないことを意味します。

具体的には、以下の問題が背景にあります。

  • テストの信頼性: test.bashはGoツールの動作を検証する重要な統合テストスイートです。テストが失敗すると、開発者はツールの変更が意図しない副作用を引き起こしていないか、または既存の機能が壊れていないかを判断できません。このコミットは、これらのテストを修正することで、テストスイートの信頼性を回復します。
  • クロスプラットフォーム互換性: Issue 4773の修正は、特にLinux環境でのテストの失敗に対処しています。これは、異なるオペレーティングシステム(特にファイルシステムの大文字・小文字の区別)がGoツールの動作に与える影響を考慮する必要があることを示しています。math/Randのような標準ライブラリのパッケージ名が、一部の環境で大文字・小文字の違いによって解決できないという問題は、クロスプラットフォーム開発における一般的な課題です。
  • goコマンドの堅牢性: go listgo 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/randmath/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 listdir1という明確なパッケージパスを評価するため、正しいルートパス($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/randmath/Randが同じファイルとして扱われる場合に、goコマンドがその重複を正しく報告するかどうかを検証することでした。
    • 修正: テストは、example/a/pkgexample/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つのファイルです。

  1. src/cmd/go/pkg_test.go:

    • このファイルは新規追加されました。
    • foldDupTestsというテストデータ構造体が定義されています。
    • TestFoldDupというテスト関数が定義されており、foldDupという(このコミットでは定義されていないが、cmd/goの他の場所で定義されていると推測される)関数をテストしています。このテストは、与えられた文字列リストの中から重複する要素を正しく識別できるかを検証します。特に、大文字・小文字の違いを考慮した重複検出のテストケースが含まれています。
  2. 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
      
      エラーメッセージの期待値文字列が変更されています。

コアとなるコードの解説

src/cmd/go/pkg_test.goTestFoldDup

この新しいテストファイルは、cmd/go内部で使用されるであろうfoldDupという関数の正確性を検証します。foldDupは、Goのパッケージパスのリストを受け取り、その中に重複する要素がないか、あるいは大文字・小文字の違いによって実質的に同じと見なされる要素がないかを検出する役割を担っていると推測されます。

例えば、{"Rand", "rand", "math", "math/rand", "math/Rand"}というテストケースでは、"Rand""rand"が重複として検出されることを期待しています。これは、Goのパッケージシステムが通常はパスの大文字・小文字を区別する一方で、Windowsのような大文字・小文字を区別しないファイルシステム上ではmath/randmath/Randが同じディレクトリを指す可能性があるため、このような「論理的な重複」を検出する必要があることを示唆しています。foldDup関数は、このような状況でgoコマンドが混乱しないように、重複するパスを適切に処理するための内部ロジックの一部であると考えられます。このテストの追加により、foldDupのロジックが堅牢であり、将来の変更によって誤って破壊されることがないように保証されます。

src/cmd/go/test.bashの修正

  1. Issue 4568のテスト修正: この修正は、go list .がシンボリックリンクされたディレクトリ内で実行された際のgoコマンドの挙動に関するものです。元のテストでは、$d/src/dir1というシンボリックリンクされたディレクトリにcdしてからgo list .を実行していました。この状況でgo listがパッケージのルートを正しく識別できず、空文字列を返していたためテストが失敗していました。 修正では、cd $d/src(シンボリックリンクの親ディレクトリ)に移動し、go list dir1と明示的にパッケージパスを指定するように変更されました。これにより、go listdir1という明確なパスを評価し、正しいルートパス($d)を返すようになります。 コミットメッセージにある「weakens the test」という記述は、この修正がgo list .がシンボリックリンクされたディレクトリ内でどのように振る舞うかという特定のコーナーケースを直接テストしなくなったことを意味します。しかし、テストの失敗を回避し、CI/CDパイプラインの健全性を維持するためには、この変更が必要でした。

  2. Issue 4773のテスト修正: この修正は、Goのパッケージシステムがファイルシステムの大文字・小文字の区別をどのように扱うかに関連するテストの信頼性を向上させます。元のテストは、math/randmath/Randというインポートを使用して、大文字・小文字が異なるパッケージ名の重複を検出することを意図していました。しかし、Linuxのような大文字・小文字を区別するファイルシステムではmath/Randというパッケージが存在しないため、インポートが失敗し、テストが意図した重複検出ロジックに到達する前に中断していました。 修正では、テストは標準ライブラリに依存する代わりに、example/a/pkgexample/a/Pkgというローカルに作成されたパッケージを使用するように変更されました。これらのパッケージは、それぞれpkg.goファイルを持つ異なるディレクトリに配置され、大文字・小文字のみが異なります。これにより、テストはファイルシステムの大文字・小文字の区別に関わらず、意図した重複検出のシナリオを確実に再現できるようになります。これは、テストがより自己完結型になり、外部環境(この場合は標準ライブラリの特定のパッケージの存在)に依存しなくなるため、テストの堅牢性が向上します。

  3. エラーメッセージの修正: これは比較的小さな変更ですが、go installコマンドがシャドウイングされたインストールパスを報告する際のエラーメッセージのフォーマットを調整するものです。元のメッセージは「no install location for directory ... hidden by ...」という形式でしたが、修正後は「no install location for ...: hidden by ...」という形式になります。 この変更は、エラーメッセージの統一性を高め、Goツールの全体的なユーザーエクスペリエンスを向上させることを目的としています。一貫性のあるエラーメッセージは、ユーザーが問題を診断し、解決するのに役立ちます。

これらの変更は、Goツールのテストスイートの信頼性を高め、異なる環境での一貫した動作を保証し、ユーザーへのエラー報告を改善することで、Go開発エコシステムの健全性に貢献しています。

関連リンク

参考にした情報源リンク