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

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

このコミットは、Go言語の cmd/nm ツールに関連するテスト (nm_test.go) の堅牢性を向上させるものです。具体的には、nm コマンドの出力が期待される3カラム未満であった場合にテストが失敗する問題を修正し、特定のOSでのテストスキップを不要にしました。

コミット

cmd/nm: do not fail TestNM if symbol has less then 3 columns in nm output

Fixes #7829

LGTM=dave
R=golang-codereviews, aram, dave
CC=golang-codereviews
https://golang.org/cl/89830043

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

https://github.com/golang/go/commit/296eeaa78df8537964821756c393cbd06174a119

元コミット内容

commit 296eeaa78df8537964821756c393cbd06174a119
Author: Alex Brainman <alex.brainman@gmail.com>
Date:   Mon Apr 21 21:12:18 2014 +1000

    cmd/nm: do not fail TestNM if symbol has less then 3 columns in nm output
    
    Fixes #7829
    
    LGTM=dave
    R=golang-codereviews, aram, dave
    CC=golang-codereviews
    https://golang.org/cl/89830043
---
 src/cmd/nm/nm_test.go | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/src/cmd/nm/nm_test.go b/src/cmd/nm/nm_test.go
index b2320bdf9f..829c844b49 100644
--- a/src/cmd/nm/nm_test.go
+++ b/src/cmd/nm/nm_test.go
@@ -19,16 +19,11 @@ import (
 var testData uint32
 
 func checkSymbols(t *testing.T, nmoutput []byte) {
-\tswitch runtime.GOOS {\n-\tcase \"linux\", \"darwin\", \"solaris\":\n-\t\tt.Skip(\"skipping test; see http://golang.org/issue/7829\")\n-\t}\n \tvar checkSymbolsFound, testDataFound bool\n \tscanner := bufio.NewScanner(bytes.NewBuffer(nmoutput))\n \tfor scanner.Scan() {\n \t\tf := strings.Fields(scanner.Text())\n \t\tif len(f) < 3 {\n-\t\t\tt.Error(\"nm must have at least 3 columns\")\n \t\t\tcontinue\n \t\t}\n \t\tswitch f[2] {\n

変更の背景

この変更は、Goの cmd/nm ツールに対するテスト (nm_test.go) が、特定の環境下で nm コマンドの出力形式の違いにより失敗するという問題(Issue #7829)を解決するために行われました。

nm コマンドは、オブジェクトファイルや実行可能ファイル内のシンボルテーブルを表示するために使用されます。その出力形式は通常、シンボルのアドレス、型、名前など、複数のカラムで構成されます。しかし、環境(OS、nm のバージョン、または入力ファイルの種類)によっては、期待されるカラム数(特に3カラム)に満たない行が出力されることがありました。

以前の nm_test.go の実装では、nm の出力行をスペースで分割し、その結果が3カラム未満であった場合に t.Error を呼び出してテストを失敗させていました。これは、nm の出力が常に特定の形式であるという前提に基づいていたため、この前提が崩れる環境ではテストが不安定になっていました。

この問題に対する一時的な回避策として、以前のコードでは linux, darwin, solaris といった特定のOSでテストをスキップする t.Skip が導入されていました。しかし、これは根本的な解決策ではなく、テストの網羅性を低下させていました。

このコミットの目的は、nm の出力形式の多様性に対応できるようテストロジックを修正し、t.Skip による回避策を削除して、より堅牢で移植性の高いテストを実現することです。

前提知識の解説

nm コマンド

nm は、Unix系システムで利用されるコマンドラインユーティリティで、オブジェクトファイル、アーカイブファイル、または実行可能ファイル内のシンボルテーブル(関数名、変数名など)をリスト表示します。出力形式は通常、以下のようになります。

アドレス 型 シンボル名

例えば、0000000000401000 T main のような形式です。ここで、0000000000401000 はシンボルのアドレス、T はシンボルの型(ここではテキストセクションのグローバルシンボル)、main はシンボル名です。このコミットで問題となったのは、この出力が常に3つのフィールド(カラム)を持つとは限らないという点です。

Goのテストフレームワーク (testing パッケージ)

Go言語には、標準ライブラリとして testing パッケージが提供されており、ユニットテストやベンチマークテストを記述するために使用されます。

  • func TestXxx(t *testing.T): テスト関数は Test で始まり、*testing.T 型の引数を取ります。
  • t.Error(args ...interface{}): テストを失敗としてマークし、指定されたメッセージを出力します。テストの実行は継続されます。
  • t.Skip(args ...interface{}): テストをスキップします。通常、特定の環境や条件でテストを実行できない場合に利用されます。

bufio.NewScannerstrings.Fields

  • bufio.NewScanner: io.Reader からデータを読み込み、行単位や単語単位でスキャンするためのユーティリティです。scanner.Scan() は次のトークン(デフォルトでは行)を読み込み、scanner.Text() でその内容を取得します。
  • strings.Fields(s string): 文字列 s を一つ以上の連続する空白文字で分割し、空でない部分文字列のスライスを返します。例えば、" a b c "["a", "b", "c"] となります。この関数は、nm コマンドの出力をカラムごとに分割するために使用されていました。

runtime.GOOS

runtime.GOOS は、Goプログラムがコンパイルまたは実行されているオペレーティングシステムを示す文字列定数です(例: "linux", "darwin", "windows")。以前のコードでは、この変数を使って特定のOSでのテストをスキップしていました。

技術的詳細

このコミットの技術的な核心は、nm コマンドの出力形式に関する誤った仮定を修正することにあります。

src/cmd/nm/nm_test.go 内の checkSymbols 関数は、nm コマンドの出力を解析し、特定のシンボルが存在するかどうかを確認する役割を担っていました。この関数は、bufio.NewScanner を使用して nm の出力を1行ずつ読み込み、strings.Fields を使って各行を空白で分割していました。

問題のコードは以下の部分でした。

		f := strings.Fields(scanner.Text())
		if len(f) < 3 {
			t.Error("nm must have at least 3 columns")
			continue
		}

このコードは、「nm の出力は常に少なくとも3つのカラムを持つ」という前提に基づいていました。もし strings.Fields が返すスライスの要素数(len(f))が3未満であった場合、それは不正な出力と見なされ、t.Error が呼び出されてテストが失敗していました。

しかし、実際には、nm コマンドの出力は、環境や入力ファイルの種類によっては、3カラム未満の行を含むことがあります。例えば、空行や、シンボル情報ではない警告メッセージなどが含まれる場合です。このような行に対して t.Error を呼び出すことは、nm コマンド自体の問題ではなく、テストが nm の出力の多様性を考慮していないことによるものでした。

このコミットでは、t.Error("nm must have at least 3 columns") の行が削除されました。これにより、len(f) < 3 の条件が満たされた場合でも、テストはエラーとしてマークされなくなります。代わりに continue が残されているため、不正な形式の行は単にスキップされ、次の行の処理に移ります。

この変更により、テストは nm の出力が常に厳密な3カラム形式であるという仮定から解放され、より柔軟になりました。結果として、以前は t.Skip で回避されていた特定のOSでのテスト失敗が解消され、テストの網羅性が向上しました。

また、この修正により、switch runtime.GOOS を使って linux, darwin, solaris でテストをスキップしていたコードブロックも不要となり、削除されました。これは、根本的な問題が解決されたため、特定の環境での回避策がもはや必要なくなったことを意味します。

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

--- a/src/cmd/nm/nm_test.go
+++ b/src/cmd/nm/nm_test.go
@@ -19,16 +19,11 @@ import (
 var testData uint32
 
 func checkSymbols(t *testing.T, nmoutput []byte) {
-\tswitch runtime.GOOS {\n-\tcase \"linux\", \"darwin\", \"solaris\":\n-\t\tt.Skip(\"skipping test; see http://golang.org/issue/7829\")\n-\t}\n \tvar checkSymbolsFound, testDataFound bool\n \tscanner := bufio.NewScanner(bytes.NewBuffer(nmoutput))\n \tfor scanner.Scan() {\n \t\tf := strings.Fields(scanner.Text())\n \t\tif len(f) < 3 {\n-\t\t\tt.Error(\"nm must have at least 3 columns\")\n \t\t\tcontinue\n \t\t}\n \t\tswitch f[2] {\n

コアとなるコードの解説

このコミットでは、src/cmd/nm/nm_test.go ファイル内の checkSymbols 関数が変更されています。

  1. switch runtime.GOOS ブロックの削除:

    -	switch runtime.GOOS {
    -	case "linux", "darwin", "solaris":
    -		t.Skip("skipping test; see http://golang.org/issue/7829")
    -	}
    

    このブロックは、以前は linux, darwin, solaris の各OSで checkSymbols テストをスキップするために使用されていました。これは、これらのOSで nm コマンドの出力形式が原因でテストが失敗する問題(Issue #7829)に対する一時的な回避策でした。今回のコミットで根本的な問題が解決されたため、このOS固有のスキップロジックは不要となり、削除されました。これにより、テストはすべてのサポート対象OSで実行されるようになり、テストの網羅性が向上しました。

  2. if len(f) < 3 ブロック内の t.Error の削除:

    -			t.Error("nm must have at least 3 columns")
    

    この行は、nm コマンドの出力行を strings.Fields で分割した結果(f)が3カラム未満であった場合に、テストをエラーとしてマークしていました。このコミットでは、この t.Error の呼び出しが削除されました。 これは、nm の出力が常に3カラム以上であるという仮定が誤りであり、環境によっては3カラム未満の行(例えば、空行や非シンボル情報)が出力される可能性があることを認識したためです。テストがこのような「不正な」行で失敗するのではなく、単にそれらを無視して処理を続行するように変更されました。

変更後のコードでは、if len(f) < 3 の条件が真の場合、continue ステートメントのみが実行されます。これにより、現在の行の残りの処理(シンボル名のチェックなど)はスキップされ、scanner.Scan() によって次の行の読み込みに進みます。この修正により、nm の出力形式が多様な環境でもテストが堅牢になり、不必要なテスト失敗が回避されるようになりました。

関連リンク

参考にした情報源リンク

  • コミットメッセージと差分 (./commit_data/19219.txt の内容)
  • Go言語の testing パッケージに関する一般的な知識
  • nm コマンドに関する一般的な知識
  • bufio および strings パッケージに関する一般的な知識
  • runtime.GOOS に関する一般的な知識