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

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

このドキュメントは、Go言語プロジェクトにおける特定のコミット(インデックス 14073)について、その内容、背景、技術的詳細、および関連する変更点を包括的に解説します。

コミット

このコミットは、Go言語のテストライブラリ testlib における rundircmpout 関数が、標準エラー出力(stderr)を適切に扱っていなかった問題を修正するものです。具体的には、テスト対象プログラムの標準出力と標準エラー出力を両方ともキャプチャし、比較対象のファイルと比較するように変更されました。

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

https://github.com/golang/go/commit/5497787d35846bbfc44719b4477d57829bc53b31

元コミット内容

commit 5497787d35846bbfc44719b4477d57829bc53b31
Author: Rémy Oudompheng <oudomphe@phare.normalesup.org>
Date:   Sun Oct 7 23:14:20 2012 +0200

    test/testlib: don't forget stderr for rundircmpout.
    
    R=golang-dev, rsc
    CC=golang-dev
    https://golang.org/cl/6620071

変更の背景

Go言語のテストスイートでは、様々なテストケースを実行し、その出力が期待される結果と一致するかどうかを検証します。testlib は、これらのテストを支援するためのシェルスクリプトベースのユーティリティライブラリです。

rundircmpout 関数は、特定のディレクトリ内のテストを実行し、その標準出力(stdout)を比較対象のファイルと比較することを目的としていました。しかし、プログラムが標準エラー出力(stderr)に何かを出力した場合、その出力は cmp コマンドにパイプされず、比較の対象外となっていました。

この問題は、テスト対象のプログラムがエラーメッセージやデバッグ情報を標準エラー出力に出力する際に、その出力がテスト結果に影響を与えない、あるいはテストが失敗しても検出されないという状況を引き起こす可能性がありました。例えば、プログラムが期待通りに動作していても、警告メッセージをstderrに出力するだけでテストが失敗すべきケースで、それが無視されてしまうといった事態です。

このコミットは、このような見落としを防ぎ、テストの網羅性と正確性を向上させるために行われました。テスト対象のプログラムが標準エラー出力に何かを出力した場合でも、それが比較対象の出力に含まれるようにすることで、より堅牢なテストが可能になります。

前提知識の解説

1. 標準入出力と標準エラー出力 (stdout, stderr)

Unix系システム(Linuxなど)では、プログラムは通常、以下の3つの標準ストリームを持っています。

  • 標準入力 (stdin): プログラムへの入力データが送られるストリーム。通常はキーボードから。
  • 標準出力 (stdout): プログラムの通常の出力データが送られるストリーム。通常は画面に表示される。
  • 標準エラー出力 (stderr): プログラムのエラーメッセージや診断情報が送られるストリーム。通常は画面に表示される。

これらはそれぞれファイルディスクリプタという番号で識別され、stdinは0、stdoutは1、stderrは2が割り当てられています。

2. シェルのリダイレクトとパイプ

シェル(bashなど)では、これらの標準ストリームの向きを変更する「リダイレクト」や、あるコマンドの出力を別のコマンドの入力に接続する「パイプ」といった機能があります。

  • > (リダイレクト): 標準出力をファイルに書き込む。例: command > file.txt
  • 2> (標準エラー出力のリダイレクト): 標準エラー出力をファイルに書き込む。例: command 2> error.log
  • | (パイプ): あるコマンドの標準出力を別のコマンドの標準入力に接続する。例: command1 | command2

3. 2>&1 の意味

2>&1 は、シェルスクリプトで非常に頻繁に使われるリダイレクトの構文です。これは「ファイルディスクリプタ2(標準エラー出力)を、ファイルディスクリプタ1(標準出力)と同じ場所にリダイレクトする」という意味を持ちます。

つまり、command 2>&1 とすると、command の標準エラー出力が標準出力と同じストリームに送られるようになります。この結果、command 2>&1 | another_command のようにパイプと組み合わせると、command の標準出力と標準エラー出力の両方が another_command の標準入力に送られることになります。

4. cmp コマンド

cmp コマンドは、2つのファイルをバイト単位で比較し、違いがあればその情報を出力します。違いがなければ何も出力せず、終了ステータスで成功(0)を返します。 cmp - file1 file2 のように使いますが、- を使うと標準入力からデータを受け取ることができます。

技術的詳細

このコミットの技術的な核心は、シェルスクリプトにおける標準出力と標準エラー出力のリダイレクトの理解と、それをテストの比較プロセスに適用することにあります。

元のコードでは、./$A.out | cmp - $D/$F.out となっていました。これは、./$A.out という実行可能ファイルの標準出力のみcmp コマンドの標準入力にパイプしていました。もし $A.out が標準エラー出力に何かを出力した場合、その内容は cmp には渡されず、テストの比較対象から漏れていました。

修正後のコードでは、./$A.out 2>&1 | cmp - $D/$F.out となっています。ここで 2>&1 が追加されています。この 2>&1 により、./$A.out の標準エラー出力(ファイルディスクリプタ2)が標準出力(ファイルディスクリプタ1)と同じストリームにリダイレクトされます。その結果、./$A.out からの標準出力と標準エラー出力の両方が結合され、単一のストリームとして cmp コマンドの標準入力にパイプされるようになります。

これにより、cmp コマンドはテスト対象プログラムの標準出力と標準エラー出力の両方をまとめて受け取り、それを期待される出力ファイル $D/$F.out と比較できるようになります。これにより、テスト対象プログラムが標準エラー出力に予期せぬメッセージを出力した場合でも、テストがそれを検出し、適切に失敗するようになります。これは、テストの信頼性と網羅性を高める上で非常に重要な変更です。

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

--- a/test/testlib
+++ b/test/testlib
@@ -53,7 +53,7 @@ rundircmpout() {
 		lastfile=$name
 	done
 	$L -o $A.out -L. $lastfile.$A
-	./$A.out | cmp - $D/$F.out
+	./$A.out 2>&1 | cmp - $D/$F.out
 }

 build() {

コアとなるコードの解説

変更は test/testlib ファイル内の rundircmpout 関数にあります。

  • 変更前:

    ./$A.out | cmp - $D/$F.out
    

    この行では、./$A.out という実行可能ファイル(テスト対象のプログラム)の標準出力のみがパイプ(|)を通じて cmp コマンドに渡されていました。cmp - $D/$F.out は、cmp コマンドが標準入力からデータを受け取り、それを $D/$F.out というファイルの内容と比較することを意味します。

  • 変更後:

    ./$A.out 2>&1 | cmp - $D/$F.out
    

    この変更では、./$A.out の直後に 2>&1 が追加されています。

    • 2 は標準エラー出力のファイルディスクリプタです。
    • > はリダイレクト演算子です。
    • &1 はファイルディスクリプタ1(標準出力)を参照することを意味します。 したがって、2>&1 は「標準エラー出力を標準出力と同じ場所にリダイレクトする」という指示になります。

    この結果、./$A.out からの標準出力と標準エラー出力の両方が結合され、単一のストリームとして cmp コマンドの標準入力にパイプされます。これにより、cmp はテスト対象プログラムのすべての出力(通常の出力とエラー出力の両方)を比較対象として扱うことができるようになり、テストの正確性が向上しました。

関連リンク

  • Go言語の変更リスト (Gerrit): https://golang.org/cl/6620071 このリンクは、GoプロジェクトのコードレビューシステムであるGerritにおけるこの変更の元のレビューページです。コミットメッセージにも記載されており、詳細な議論や関連する変更履歴を確認できます。

参考にした情報源リンク

  • Go言語の公式ドキュメント: Go言語のテストに関する一般的な情報や、testlib のような内部ユーティリティの文脈を理解するために参照しました。
  • Unix/Linux シェルスクリプトのリダイレクトに関するドキュメント: 2>&1 のようなシェルリダイレクトの構文と動作を理解するために参照しました。
  • cmp コマンドのマニュアルページ: cmp コマンドの機能と、標準入力から比較を行うための - オプションの使用法を確認するために参照しました。

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

このドキュメントは、Go言語プロジェクトにおける特定のコミット(インデックス 14073)について、その内容、背景、技術的詳細、および関連する変更点を包括的に解説します。

コミット

このコミットは、Go言語のテストライブラリ testlib における rundircmpout 関数が、標準エラー出力(stderr)を適切に扱っていなかった問題を修正するものです。具体的には、テスト対象プログラムの標準出力と標準エラー出力を両方ともキャプチャし、比較対象のファイルと比較するように変更されました。

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

https://github.com/golang/go/commit/5497787d35846bbfc44719b4477d57829bc53b31

元コミット内容

commit 5497787d35846bbfc44719b4477d57829bc53b31
Author: Rémy Oudompheng <oudomphe@phare.normalesup.org>
Date:   Sun Oct 7 23:14:20 2012 +0200

    test/testlib: don't forget stderr for rundircmpout.
    
    R=golang-dev, rsc
    CC=golang-dev
    https://golang.org/cl/6620071

変更の背景

Go言語のテストスイートでは、様々なテストケースを実行し、その出力が期待される結果と一致するかどうかを検証します。testlib は、これらのテストを支援するためのシェルスクリプトベースのユーティリティライブラリです。

rundircmpout 関数は、特定のディレクトリ内のテストを実行し、その標準出力(stdout)を比較対象のファイルと比較することを目的としていました。しかし、プログラムが標準エラー出力(stderr)に何かを出力した場合、その出力は cmp コマンドにパイプされず、比較の対象外となっていました。

この問題は、テスト対象のプログラムがエラーメッセージやデバッグ情報を標準エラー出力に出力する際に、その出力がテスト結果に影響を与えない、あるいはテストが失敗しても検出されないという状況を引き起こす可能性がありました。例えば、プログラムが期待通りに動作していても、警告メッセージをstderrに出力するだけでテストが失敗すべきケースで、それが無視されてしまうといった事態です。

このコミットは、このような見落としを防ぎ、テストの網羅性と正確性を向上させるために行われました。テスト対象のプログラムが標準エラー出力に何かを出力した場合でも、それが比較対象の出力に含まれるようにすることで、より堅牢なテストが可能になります。

前提知識の解説

1. 標準入出力と標準エラー出力 (stdout, stderr)

Unix系システム(Linuxなど)では、プログラムは通常、以下の3つの標準ストリームを持っています。

  • 標準入力 (stdin): プログラムへの入力データが送られるストリーム。通常はキーボードから。
  • 標準出力 (stdout): プログラムの通常の出力データが送られるストリーム。通常は画面に表示される。
  • 標準エラー出力 (stderr): プログラムのエラーメッセージや診断情報が送られるストリーム。通常は画面に表示される。

これらはそれぞれファイルディスクリプタという番号で識別され、stdinは0、stdoutは1、stderrは2が割り当てられています。

2. シェルのリダイレクトとパイプ

シェル(bashなど)では、これらの標準ストリームの向きを変更する「リダイレクト」や、あるコマンドの出力を別のコマンドの入力に接続する「パイプ」といった機能があります。

  • > (リダイレクト): 標準出力をファイルに書き込む。例: command > file.txt
  • 2> (標準エラー出力のリダイレクト): 標準エラー出力をファイルに書き込む。例: command 2> error.log
  • | (パイプ): あるコマンドの標準出力を別のコマンドの標準入力に接続する。例: command1 | command2

3. 2>&1 の意味

2>&1 は、シェルスクリプトで非常に頻繁に使われるリダイレクトの構文です。これは「ファイルディスクリプタ2(標準エラー出力)を、ファイルディスクリプタ1(標準出力)と同じ場所にリダイレクトする」という意味を持ちます。

つまり、command 2>&1 とすると、command の標準エラー出力が標準出力と同じストリームに送られるようになります。この結果、command 2>&1 | another_command のようにパイプと組み合わせると、command の標準出力と標準エラー出力の両方が another_command の標準入力に送られることになります。

4. cmp コマンド

cmp コマンドは、2つのファイルをバイト単位で比較し、違いがあればその情報を出力します。違いがなければ何も出力せず、終了ステータスで成功(0)を返します。 cmp - file1 file2 のように使いますが、- を使うと標準入力からデータを受け取ることができます。

技術的詳細

このコミットの技術的な核心は、シェルスクリプトにおける標準出力と標準エラー出力のリダイレクトの理解と、それをテストの比較プロセスに適用することにあります。

元のコードでは、./$A.out | cmp - $D/$F.out となっていました。これは、./$A.out という実行可能ファイルの標準出力のみcmp コマンドの標準入力にパイプしていました。もし $A.out が標準エラー出力に何かを出力した場合、その内容は cmp には渡されず、テストの比較対象から漏れていました。

修正後のコードでは、./$A.out 2>&1 | cmp - $D/$F.out となっています。ここで 2>&1 が追加されています。この 2>&1 により、./$A.out の標準エラー出力(ファイルディスクリプタ2)が標準出力(ファイルディスクリプタ1)と同じストリームにリダイレクトされます。その結果、./$A.out からの標準出力と標準エラー出力の両方が結合され、単一のストリームとして cmp コマンドの標準入力にパイプされるようになります。

これにより、cmp コマンドはテスト対象プログラムの標準出力と標準エラー出力の両方をまとめて受け取り、それを期待される出力ファイル $D/$F.out と比較できるようになります。これにより、テスト対象プログラムが標準エラー出力に予期せぬメッセージを出力した場合でも、テストがそれを検出し、適切に失敗するようになります。これは、テストの信頼性と網羅性を高める上で非常に重要な変更です。

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

--- a/test/testlib
+++ b/test/testlib
@@ -53,7 +53,7 @@ rundircmpout() {
 		lastfile=$name
 	done
 	$L -o $A.out -L. $lastfile.$A
-	./$A.out | cmp - $D/$F.out
+	./$A.out 2>&1 | cmp - $D/$F.out
 }

 build() {

コアとなるコードの解説

変更は test/testlib ファイル内の rundircmpout 関数にあります。

  • 変更前:

    ./$A.out | cmp - $D/$F.out
    

    この行では、./$A.out という実行可能ファイル(テスト対象のプログラム)の標準出力のみがパイプ(|)を通じて cmp コマンドに渡されていました。cmp - $D/$F.out は、cmp コマンドが標準入力からデータを受け取り、それを $D/$F.out というファイルの内容と比較することを意味します。

  • 変更後:

    ./$A.out 2>&1 | cmp - $D/$F.out
    

    この変更では、./$A.out の直後に 2>&1 が追加されています。

    • 2 は標準エラー出力のファイルディスクリプタです。
    • > はリダイレクト演算子です。
    • &1 はファイルディスクリプタ1(標準出力)を参照することを意味します。 したがって、2>&1 は「標準エラー出力を標準出力と同じ場所にリダイレクトする」という指示になります。

    この結果、./$A.out からの標準出力と標準エラー出力の両方が結合され、単一のストリームとして cmp コマンドの標準入力にパイプされます。これにより、cmp はテスト対象プログラムのすべての出力(通常の出力とエラー出力の両方)を比較対象として扱うことができるようになり、テストの正確性が向上しました。

関連リンク

  • Go言語の変更リスト (Gerrit): https://golang.org/cl/6620071 このリンクは、GoプロジェクトのコードレビューシステムであるGerritにおけるこの変更の元のレビューページです。コミットメッセージにも記載されており、詳細な議論や関連する変更履歴を確認できます。

参考にした情報源リンク

  • Go言語の公式ドキュメント: Go言語のテストに関する一般的な情報や、testlib のような内部ユーティリティの文脈を理解するために参照しました。
  • Unix/Linux シェルスクリプトのリダイレクトに関するドキュメント: 2>&1 のようなシェルリダイレクトの構文と動作を理解するために参照しました。
  • cmp コマンドのマニュアルページ: cmp コマンドの機能と、標準入力から比較を行うための - オプションの使用法を確認するために参照しました。