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

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

このコミットは、Go言語のcmd/nmツールのテストファイルであるsrc/cmd/nm/nm_test.goに対する変更です。nmツールは、Unix系のシステムにおける同名のコマンドと同様に、実行可能ファイルやオブジェクトファイルのシンボルテーブルを検査するために使用されます。このテストファイルは、nmツールのビルドと実行が正しく行われることを検証します。

コミット

commit 2a7ab1616f861087c6da320f7de360949868384a
Author: Alex Brainman <alex.brainman@gmail.com>
Date:   Mon May 12 09:26:05 2014 +1000

    cmd/nm: do not write to GOROOT testdata directories during TestNM
    
    LGTM=bradfitz
    R=bradfitz, 0intro
    CC=golang-codereviews
    https://golang.org/cl/95280043

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/2a7ab1616f861087c6da320f7de360949868384a

元コミット内容

cmd/nm: do not write to GOROOT testdata directories during TestNM

LGTM=bradfitz
R=bradfitz, 0intro
CC=golang-codereviews
https://golang.org/cl/95280043

変更の背景

このコミットの背景には、Goのテストフレームワークにおける一般的な問題、特にテストが実行される環境のクリーンさを保つという課題があります。以前のTestNMの実装では、go build -o testnm.exe cmd/nmコマンドを使用してtestnm.exeという実行ファイルをテストが実行されるディレクトリ(多くの場合、GOROOT内のソースディレクトリ)に直接生成していました。

このアプローチにはいくつかの問題がありました。

  1. 作業ディレクトリの汚染: テストが実行されるたびに、testnm.exeというファイルがソースコードリポジトリ内に生成され、テスト終了後に削除されるものの、一時的に作業ディレクトリを汚染していました。これは、特に並行してテストが実行される場合や、テストが異常終了した場合に問題を引き起こす可能性がありました。
  2. GOROOTの整合性: GOROOTはGoのインストールディレクトリであり、その内容は通常、Goの配布物の一部として管理されるべきです。テストがGOROOT内のディレクトリにファイルを書き込むことは、GOROOTの整合性を損なう可能性があり、予期せぬ副作用やビルド環境の不安定化を招く恐れがありました。
  3. クリーンアップの信頼性: defer os.Remove("testnm.exe")によるクリーンアップは、テストが正常に終了した場合にのみ機能します。テストがパニックを起こしたり、予期せぬエラーで終了したりした場合、testnm.exeが残ってしまう可能性がありました。

これらの問題を解決し、テストの独立性と信頼性を高めるために、テスト中に生成される一時ファイルをGOROOTの外部にある一時ディレクトリに配置し、テスト終了後に確実にクリーンアップする変更が必要とされました。

前提知識の解説

go build

go buildコマンドは、Goのソースコードをコンパイルして実行可能ファイルやパッケージを生成するために使用されます。-oフラグを使用すると、出力される実行可能ファイルの名前とパスを指定できます。

cmd/nm

cmd/nmは、Goツールチェーンの一部として提供されるnmコマンドの実装です。nmは"name list"の略で、Unix系のシステムで広く使われているユーティリティです。実行可能ファイル、オブジェクトファイル、共有ライブラリなどのバイナリファイルに含まれるシンボル(関数名、変数名など)のリストを表示するために使用されます。デバッグやバイナリの解析に役立ちます。

GOROOT

GOROOTは、Go言語のインストールディレクトリを指す環境変数です。Goの標準ライブラリ、ツール、ドキュメントなどがこのディレクトリに格納されています。Goのビルドシステムは、このGOROOTパスを基にGoの標準パッケージやツールを見つけます。

testdataディレクトリ

Goのテストでは、テストに必要なデータファイルをtestdataという名前のディレクトリに配置する慣習があります。go testコマンドは、testdataディレクトリを特別扱いし、テスト実行時にその内容をテストバイナリに含めたり、テストコードからアクセスできるようにしたりします。このコミットで言及されているGOROOT testdata directoriesは、Goの標準ライブラリやツールのテストデータが格納されているディレクトリを指します。

io/ioutilパッケージ

io/ioutilパッケージは、Go 1.16で非推奨となり、Go 1.18で削除されましたが、このコミットが作成された2014年当時は、ファイルやディレクトリのI/O操作を簡素化するためのユーティリティ関数を提供していました。特に、ioutil.TempDir関数は一時ディレクトリを作成するために使用されます。

ioutil.TempDir(dir, pattern)

この関数は、指定されたdirディレクトリ内に、指定されたpatternに基づいてユニークな名前の一時ディレクトリを作成します。dirが空文字列の場合、システムのデフォルトの一時ディレクトリ(例: /tmp)が使用されます。この関数は作成された一時ディレクトリのパスを返します。

os.RemoveAll(path)

この関数は、指定されたパスにあるファイルまたはディレクトリ(およびその中のすべての内容)を再帰的に削除します。一時ディレクトリのクリーンアップによく使用されます。

deferステートメント

Go言語のdeferステートメントは、そのステートメントを含む関数がリターンする直前に、指定された関数呼び出しを実行することを保証します。これは、リソースの解放(ファイルのクローズ、ロックの解除、一時ディレクトリの削除など)を確実に行うために非常に便利です。たとえ関数がエラーで終了しても、deferされた関数は実行されます。

技術的詳細

このコミットの技術的な核心は、テスト中に生成される一時的な実行ファイルtestnm.exeの配置場所を、永続的なソースツリー内から一時ディレクトリへと変更することにあります。

具体的な変更点は以下の通りです。

  1. io/ioutilのインポート: 一時ディレクトリを作成するために、io/ioutilパッケージがインポートされます。
  2. 一時ディレクトリの作成:
    tmpDir, err := ioutil.TempDir("", "TestNM")
    if err != nil {
        t.Fatal("TempDir failed: ", err)
    }
    
    ioutil.TempDir("", "TestNM")を呼び出すことで、システムのデフォルトの一時ディレクトリ(例: /tmp)内にTestNMというプレフィックスを持つユニークな名前の一時ディレクトリが作成されます。このディレクトリのパスはtmpDir変数に格納されます。エラーが発生した場合は、テストが失敗します。
  3. 一時ディレクトリの確実なクリーンアップ:
    defer os.RemoveAll(tmpDir)
    
    deferステートメントを使用してos.RemoveAll(tmpDir)が呼び出されます。これにより、TestNM関数が終了する際に(正常終了、エラー終了、パニックのいずれであっても)、作成された一時ディレクトリとその内容が確実に削除されます。これは、テスト後の環境をクリーンに保つ上で非常に重要です。
  4. testnm.exeのビルドパスの変更:
    // 変更前:
    // out, err := exec.Command("go", "build", "-o", "testnm.exe", "cmd/nm").CombinedOutput()
    // defer os.Remove("testnm.exe")
    
    // 変更後:
    testnmpath := filepath.Join(tmpDir, "testnm.exe")
    out, err := exec.Command("go", "build", "-o", testnmpath, "cmd/nm").CombinedOutput()
    
    testnm.exeの出力先が、現在のディレクトリから新しく作成された一時ディレクトリ内のパス(testnmpath)に変更されます。これにより、testnm.exeがソースツリーを汚染することがなくなります。また、一時ディレクトリ全体がos.RemoveAllで削除されるため、個別のos.Remove("testnm.exe")は不要になります。
  5. testnm.exeの実行パスの変更:
    // 変更前:
    // cmd := exec.Command("./testnm.exe", exepath)
    // cmd := exec.Command("./testnm.exe", os.Args[0])
    
    // 変更後:
    cmd := exec.Command(testnmpath, exepath)
    cmd := exec.Command(testnmpath, os.Args[0])
    
    testnm.exeを実行する際のパスも、相対パス./testnm.exeから、一時ディレクトリ内の絶対パスtestnmpathに変更されます。これにより、テストがどこから実行されても、正しいtestnm.exeが参照されることが保証されます。

これらの変更により、TestNMはより堅牢になり、テスト環境への副作用を最小限に抑えることができるようになりました。

コアとなるコードの変更箇所

--- a/src/cmd/nm/nm_test.go
+++ b/src/cmd/nm/nm_test.go
@@ -8,6 +8,7 @@ import (
 	"bufio"
 	"bytes"
 	"fmt"
+	"io/ioutil"
 	"os"
 	"os/exec"
 	"path/filepath"
@@ -54,11 +55,17 @@ func checkSymbols(t *testing.T, nmoutput []byte) {
 }
 
 func TestNM(t *testing.T) {
-	out, err := exec.Command("go", "build", "-o", "testnm.exe", "cmd/nm").CombinedOutput()
+	tmpDir, err := ioutil.TempDir("", "TestNM")
 	if err != nil {
-		t.Fatalf("go build -o testnm.exe cmd/nm: %v\n%s", err, string(out))
+		t.Fatal("TempDir failed: ", err)
+	}
+	defer os.RemoveAll(tmpDir)
+
+	testnmpath := filepath.Join(tmpDir, "testnm.exe")
+	out, err := exec.Command("go", "build", "-o", testnmpath, "cmd/nm").CombinedOutput()
+	if err != nil {
+		t.Fatalf("go build -o %v cmd/nm: %v\n%s", testnmpath, err, string(out))
 	}
-	defer os.Remove("testnm.exe")
 
 	testfiles := []string{
 		"elf/testdata/gcc-386-freebsd-exec",
@@ -72,14 +79,14 @@ func TestNM(t *testing.T) {
 	}
 	for _, f := range testfiles {
 		exepath := filepath.Join(runtime.GOROOT(), "src", "pkg", "debug", f)
-		cmd := exec.Command("./testnm.exe", exepath)
+		cmd := exec.Command(testnmpath, exepath)
 		out, err := cmd.CombinedOutput()
 		if err != nil {
 			t.Fatalf("go tool nm %v: %v\\n%s", exepath, err, string(out))
 		}
 	}
 
-	cmd := exec.Command("./testnm.exe", os.Args[0])
+	cmd := exec.Command(testnmpath, os.Args[0])
 	out, err = cmd.CombinedOutput()
 	if err != nil {
 		t.Fatalf("go tool nm %v: %v\\n%s", os.Args[0], err, string(out))

コアとなるコードの解説

  1. + "io/ioutil": io/ioutilパッケージが新しくインポートされました。これは、一時ディレクトリを作成するためのioutil.TempDir関数を使用するために必要です。

  2. - out, err := exec.Command("go", "build", "-o", "testnm.exe", "cmd/nm").CombinedOutput(): testnm.exeを現在のディレクトリにビルドしていた元の行が削除されました。

  3. + tmpDir, err := ioutil.TempDir("", "TestNM"): ioutil.TempDir関数を呼び出して、システムの一時ディレクトリ内にTestNMというプレフィックスを持つ新しい一時ディレクトリを作成します。このディレクトリのパスはtmpDir変数に格納されます。

  4. + if err != nil { t.Fatal("TempDir failed: ", err) }: ioutil.TempDirの呼び出しでエラーが発生した場合のハンドリングです。エラーが発生した場合は、テストを即座に終了させます。

  5. + defer os.RemoveAll(tmpDir): deferステートメントにより、TestNM関数が終了する際にos.RemoveAll(tmpDir)が実行されることが保証されます。これにより、作成された一時ディレクトリとその内容(testnm.exeを含む)が確実に削除され、テスト後の環境がクリーンに保たれます。

  6. - defer os.Remove("testnm.exe"): 以前のtestnm.exeを個別に削除するdeferステートメントは、一時ディレクトリ全体を削除するdefer os.RemoveAll(tmpDir)によって不要になったため削除されました。

  7. + testnmpath := filepath.Join(tmpDir, "testnm.exe"): 新しく作成された一時ディレクトリtmpDirの中にtestnm.exeという名前で実行ファイルを配置するための完全なパスを構築します。

  8. + out, err := exec.Command("go", "build", "-o", testnmpath, "cmd/nm").CombinedOutput(): go buildコマンドの出力先が、現在のディレクトリからtestnmpath(一時ディレクトリ内のパス)に変更されました。これにより、ビルドされた実行ファイルが一時ディレクトリに格納されます。

  9. + if err != nil { t.Fatalf("go build -o %v cmd/nm: %v\\n%s", testnmpath, err, string(out)) }: ビルドコマンドでエラーが発生した場合のハンドリングです。エラーメッセージには、ビルド先のパスtestnmpathが含まれるようになりました。

  10. - cmd := exec.Command("./testnm.exe", exepath) および - cmd := exec.Command("./testnm.exe", os.Args[0]): testnm.exeを実行する際に、相対パス./testnm.exeを使用していた行が削除されました。

  11. + cmd := exec.Command(testnmpath, exepath) および + cmd := exec.Command(testnmpath, os.Args[0]): testnm.exeを実行する際に、一時ディレクトリ内にビルドされた実行ファイルの絶対パスtestnmpathを使用するように変更されました。これにより、テストの実行場所に関わらず、正しいtestnm.exeが確実に実行されます。

これらの変更により、TestNMはより堅牢で、テスト環境に副作用を与えないようになりました。

関連リンク

参考にした情報源リンク

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

このコミットは、Go言語の`cmd/nm`ツールのテストファイルである`src/cmd/nm/nm_test.go`に対する変更です。`nm`ツールは、Unix系のシステムにおける同名のコマンドと同様に、実行可能ファイルやオブジェクトファイルのシンボルテーブルを検査するために使用されます。このテストファイルは、`nm`ツールのビルドと実行が正しく行われることを検証します。

## コミット

commit 2a7ab1616f861087c6da320f7de360949868384a Author: Alex Brainman alex.brainman@gmail.com Date: Mon May 12 09:26:05 2014 +1000

cmd/nm: do not write to GOROOT testdata directories during TestNM

LGTM=bradfitz
R=bradfitz, 0intro
CC=golang-codereviews
https://golang.org/cl/95280043

## GitHub上でのコミットページへのリンク

[https://github.com/golang/go/commit/2a7ab1616f861087c6da320f7de360949868384a](https://github.com/golang/go/commit/2a7ab1616f861087c6da320f7de360949868384a)

## 元コミット内容

cmd/nm: do not write to GOROOT testdata directories during TestNM

LGTM=bradfitz R=bradfitz, 0intro CC=golang-codereviews https://golang.org/cl/95280043


## 変更の背景

このコミットの背景には、Goのテストフレームワークにおける一般的な問題、特にテストが実行される環境のクリーンさを保つという課題があります。以前の`TestNM`の実装では、`go build -o testnm.exe cmd/nm`コマンドを使用して`testnm.exe`という実行ファイルをテストが実行されるディレクトリ(多くの場合、`GOROOT`内のソースディレクトリ)に直接生成していました。

このアプローチにはいくつかの問題がありました。
1.  **作業ディレクトリの汚染**: テストが実行されるたびに、`testnm.exe`というファイルがソースコードリポジトリ内に生成され、テスト終了後に削除されるものの、一時的に作業ディレクトリを汚染していました。これは、特に並行してテストが実行される場合や、テストが異常終了した場合に問題を引き起こす可能性がありました。
2.  **`GOROOT`の整合性**: `GOROOT`はGoのインストールディレクトリであり、その内容は通常、Goの配布物の一部として管理されるべきです。テストが`GOROOT`内のディレクトリにファイルを書き込むことは、`GOROOT`の整合性を損なう可能性があり、予期せぬ副作用やビルド環境の不安定化を招く恐れがありました。
3.  **クリーンアップの信頼性**: `defer os.Remove("testnm.exe")`によるクリーンアップは、テストが正常に終了した場合にのみ機能します。テストがパニックを起こしたり、予期せぬエラーで終了したりした場合、`testnm.exe`が残ってしまう可能性がありました。

これらの問題を解決し、テストの独立性と信頼性を高めるために、テスト中に生成される一時ファイルを`GOROOT`の外部にある一時ディレクトリに配置し、テスト終了後に確実にクリーンアップする変更が必要とされました。

## 前提知識の解説

### `go build`
`go build`コマンドは、Goのソースコードをコンパイルして実行可能ファイルやパッケージを生成するために使用されます。`-o`フラグを使用すると、出力される実行可能ファイルの名前とパスを指定できます。

### `cmd/nm`
`cmd/nm`は、Goツールチェーンの一部として提供される`nm`コマンドの実装です。`nm`は"name list"の略で、Unix系のシステムで広く使われているユーティリティです。実行可能ファイル、オブジェクトファイル、共有ライブラリなどのバイナリファイルに含まれるシンボル(関数名、変数名など)のリストを表示するために使用されます。デバッグやバイナリの解析に役立ちます。

### `GOROOT`
`GOROOT`は、Go言語のインストールディレクトリを指す環境変数です。Goの標準ライブラリ、ツール、ドキュメントなどがこのディレクトリに格納されています。Goのビルドシステムは、この`GOROOT`パスを基にGoの標準パッケージやツールを見つけます。

### `testdata`ディレクトリ
Goのテストでは、テストに必要なデータファイルを`testdata`という名前のディレクトリに配置する慣習があります。`go test`コマンドは、`testdata`ディレクトリを特別扱いし、テスト実行時にその内容をテストバイナリに含めたり、テストコードからアクセスできるようにしたりします。このコミットで言及されている`GOROOT testdata directories`は、Goの標準ライブラリやツールのテストデータが格納されているディレクトリを指します。

### `io/ioutil`パッケージ
`io/ioutil`パッケージは、Go 1.16で非推奨となり、Go 1.18で削除されましたが、このコミットが作成された2014年当時は、ファイルやディレクトリのI/O操作を簡素化するためのユーティリティ関数を提供していました。特に、`ioutil.TempDir`関数は一時ディレクトリを作成するために使用されます。

### `ioutil.TempDir(dir, pattern)`
この関数は、指定された`dir`ディレクトリ内に、指定された`pattern`に基づいてユニークな名前の一時ディレクトリを作成します。`dir`が空文字列の場合、システムのデフォルトの一時ディレクトリ(例: `/tmp`)が使用されます。この関数は作成された一時ディレクトリのパスを返します。

### `os.RemoveAll(path)`
この関数は、指定されたパスにあるファイルまたはディレクトリ(およびその中のすべての内容)を再帰的に削除します。一時ディレクトリのクリーンアップによく使用されます。

### `defer`ステートメント
Go言語の`defer`ステートメントは、そのステートメントを含む関数がリターンする直前に、指定された関数呼び出しを実行することを保証します。これは、リソースの解放(ファイルのクローズ、ロックの解除、一時ディレクトリの削除など)を確実に行うために非常に便利です。たとえ関数がエラーで終了しても、`defer`された関数は実行されます。

## 技術的詳細

このコミットの技術的な核心は、テスト中に生成される一時的な実行ファイル`testnm.exe`の配置場所を、永続的なソースツリー内から一時ディレクトリへと変更することにあります。

具体的な変更点は以下の通りです。

1.  **`io/ioutil`のインポート**: 一時ディレクトリを作成するために、`io/ioutil`パッケージがインポートされます。
2.  **一時ディレクトリの作成**:
    ```go
    tmpDir, err := ioutil.TempDir("", "TestNM")
    if err != nil {
        t.Fatal("TempDir failed: ", err)
    }
    ```
    `ioutil.TempDir("", "TestNM")`を呼び出すことで、システムのデフォルトの一時ディレクトリ(例: `/tmp`)内に`TestNM`というプレフィックスを持つユニークな名前の一時ディレクトリが作成されます。このディレクトリのパスは`tmpDir`変数に格納されます。エラーが発生した場合は、テストが失敗します。
3.  **一時ディレクトリの確実なクリーンアップ**:
    ```go
    defer os.RemoveAll(tmpDir)
    ```
    `defer`ステートメントを使用して`os.RemoveAll(tmpDir)`が呼び出されます。これにより、`TestNM`関数が終了する際に(正常終了、エラー終了、パニックのいずれであっても)、作成された一時ディレクトリとその内容が確実に削除されます。これは、テスト後の環境をクリーンに保つ上で非常に重要です。
4.  **`testnm.exe`のビルドパスの変更**:
    ```go
    // 変更前:
    // out, err := exec.Command("go", "build", "-o", "testnm.exe", "cmd/nm").CombinedOutput()
    // defer os.Remove("testnm.exe")

    // 変更後:
    testnmpath := filepath.Join(tmpDir, "testnm.exe")
    out, err := exec.Command("go", "build", "-o", testnmpath, "cmd/nm").CombinedOutput()
    ```
    `testnm.exe`の出力先が、現在のディレクトリから新しく作成された一時ディレクトリ内のパス(`testnmpath`)に変更されます。これにより、`testnm.exe`がソースツリーを汚染することがなくなります。また、一時ディレクトリ全体が`os.RemoveAll`で削除されるため、個別の`os.Remove("testnm.exe")`は不要になります。
5.  **`testnm.exe`の実行パスの変更**:
    ```go
    // 変更前:
    // cmd := exec.Command("./testnm.exe", exepath)
    // cmd := exec.Command("./testnm.exe", os.Args[0])

    // 変更後:
    cmd := exec.Command(testnmpath, exepath)
    cmd := exec.Command(testnmpath, os.Args[0])
    ```
    `testnm.exe`を実行する際のパスも、相対パス`./testnm.exe`から、一時ディレクトリ内の絶対パス`testnmpath`に変更されます。これにより、テストがどこから実行されても、正しい`testnm.exe`が参照されることが保証されます。

これらの変更により、`TestNM`はより堅牢になり、テスト環境への副作用を最小限に抑えることができるようになりました。

## コアとなるコードの変更箇所

```diff
--- a/src/cmd/nm/nm_test.go
+++ b/src/cmd/nm/nm_test.go
@@ -8,6 +8,7 @@ import (
 	"bufio"
 	"bytes"
 	"fmt"
+	"io/ioutil"
 	"os"
 	"os/exec"
 	"path/filepath"
@@ -54,11 +55,17 @@ func checkSymbols(t *testing.T, nmoutput []byte) {
 }
 
 func TestNM(t *testing.T) {
-	out, err := exec.Command("go", "build", "-o", "testnm.exe", "cmd/nm").CombinedOutput()
+	tmpDir, err := ioutil.TempDir("", "TestNM")
 	if err != nil {
-		t.Fatalf("go build -o testnm.exe cmd/nm: %v\\n%s", err, string(out))
+		t.Fatal("TempDir failed: ", err)
+	}
+	defer os.RemoveAll(tmpDir)
+
+	testnmpath := filepath.Join(tmpDir, "testnm.exe")
+	out, err := exec.Command("go", "build", "-o", testnmpath, "cmd/nm").CombinedOutput()
+	if err != nil {
+		t.Fatalf("go build -o %v cmd/nm: %v\\n%s", testnmpath, err, string(out))
 	}
-	defer os.Remove("testnm.exe")
 
 	testfiles := []string{
 		"elf/testdata/gcc-386-freebsd-exec",
@@ -72,14 +79,14 @@ func TestNM(t *testing.T) {
 	}
 	for _, f := range testfiles {
 		exepath := filepath.Join(runtime.GOROOT(), "src", "pkg", "debug", f)
-		cmd := exec.Command("./testnm.exe", exepath)
+		cmd := exec.Command(testnmpath, exepath)
 		out, err := cmd.CombinedOutput()
 		if err != nil {
 			t.Fatalf("go tool nm %v: %v\\n%s", exepath, err, string(out))
 		}
 	}
 
-	cmd := exec.Command("./testnm.exe", os.Args[0])
+	cmd := exec.Command(testnmpath, os.Args[0])
 	out, err = cmd.CombinedOutput()
 	if err != nil {
 		t.Fatalf("go tool nm %v: %v\\n%s", os.Args[0], err, string(out))

コアとなるコードの解説

  1. + "io/ioutil": io/ioutilパッケージが新しくインポートされました。これは、一時ディレクトリを作成するためのioutil.TempDir関数を使用するために必要です。

  2. - out, err := exec.Command("go", "build", "-o", "testnm.exe", "cmd/nm").CombinedOutput(): testnm.exeを現在のディレクトリにビルドしていた元の行が削除されました。

  3. + tmpDir, err := ioutil.TempDir("", "TestNM"): ioutil.TempDir関数を呼び出して、システムの一時ディレクトリ内にTestNMというプレフィックスを持つ新しい一時ディレクトリを作成します。このディレクトリのパスはtmpDir変数に格納されます。

  4. + if err != nil { t.Fatal("TempDir failed: ", err) }: ioutil.TempDirの呼び出しでエラーが発生した場合のハンドリングです。エラーが発生した場合は、テストを即座に終了させます。

  5. + defer os.RemoveAll(tmpDir): deferステートメントにより、TestNM関数が終了する際にos.RemoveAll(tmpDir)が実行されることが保証されます。これにより、作成された一時ディレクトリとその内容(testnm.exeを含む)が確実に削除され、テスト後の環境がクリーンに保たれます。

  6. - defer os.Remove("testnm.exe"): 以前のtestnm.exeを個別に削除するdeferステートメントは、一時ディレクトリ全体を削除するdefer os.RemoveAll(tmpDir)によって不要になったため削除されました。

  7. + testnmpath := filepath.Join(tmpDir, "testnm.exe"): 新しく作成された一時ディレクトリtmpDirの中にtestnm.exeという名前で実行ファイルを配置するための完全なパスを構築します。

  8. + out, err := exec.Command("go", "build", "-o", testnmpath, "cmd/nm").CombinedOutput(): go buildコマンドの出力先が、現在のディレクトリからtestnmpath(一時ディレクトリ内のパス)に変更されました。これにより、ビルドされた実行ファイルが一時ディレクトリに格納されます。

  9. + if err != nil { t.Fatalf("go build -o %v cmd/nm: %v\\n%s", testnmpath, err, string(out)) }: ビルドコマンドでエラーが発生した場合のハンドリングです。エラーメッセージには、ビルド先のパスtestnmpathが含まれるようになりました。

  10. - cmd := exec.Command("./testnm.exe", exepath) および - cmd := exec.Command("./testnm.exe", os.Args[0]): testnm.exeを実行する際に、相対パス./testnm.exeを使用していた行が削除されました。

  11. + cmd := exec.Command(testnmpath, exepath) および + cmd := exec.Command(testnmpath, os.Args[0]): testnm.exeを実行する際に、一時ディレクトリ内にビルドされた実行ファイルの絶対パスtestnmpathを使用するように変更されました。これにより、テストの実行場所に関わらず、正しいtestnm.exeが確実に実行されます。

これらの変更により、TestNMはより堅牢で、テスト環境に副作用を与えないようになりました。

関連リンク

参考にした情報源リンク