[インデックス 18789] ファイルの概要
このコミットは、Go言語のツールチェイン、特にgo test -cover
コマンドにおけるcgo
コードのテストカバレッジに関するものです。具体的には、cgo
を利用したGoパッケージのコードカバレッジが正しく機能するかどうかを検証するための新しいテストケースを追加しています。このテストケースは、以前の変更(CL 34680044)がcgo
を含むプロジェクトのカバレッジ測定に与える影響を評価するために導入されました。
コミット
- コミットハッシュ:
9abcd53eda0629d009941027ffa2dc680b5f1d00
- Author: Russ Cox rsc@golang.org
- Date: Thu Mar 6 18:36:32 2014 -0500
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/9abcd53eda0629d009941027ffa2dc680b5f1d00
元コミット内容
cmd/go: add test case for cgo coverage
This is a test case for CL 34680044.
Fixes #6333.
LGTM=bradfitz
R=golang-codereviews, bradfitz, minux.ma
CC=golang-codereviews
https://golang.org/cl/71230049
変更の背景
このコミットの主な背景は、Go言語のgo test -cover
コマンドがcgo
で記述されたコードに対して、期待通りにカバレッジを測定できるかを検証することにあります。コミットメッセージには「This is a test case for CL 34680044. Fixes #6333.」と記載されています。
CL 34680044
は、おそらくcgo
を含むGoパッケージのコードカバレッジ測定に関する修正や改善を導入した変更リスト(Change List)を指しています。このコミットは、その変更が意図した通りに機能するかを確認するためのテストを追加するものです。
Fixes #6333
は、GoのIssueトラッカーにおける問題番号を示していますが、現在の検索ではこの特定のIssueに関する詳細な情報は見つかりませんでした。しかし、文脈から判断すると、このIssueはcgo
とコードカバレッジの連携における何らかの問題を報告していた可能性が高いです。GoのコードカバレッジツールはGoコードの計測に特化しており、cgo
を介して呼び出されるCコードの直接的なカバレッジ測定は、Goの標準ツールではサポートされていません。そのため、このテストケースは、cgo
が関与するGoコード部分のカバレッジが正しく報告されることを確認することを目的としていると考えられます。
前提知識の解説
Go言語のコードカバレッジ
Go言語には、go test -cover
コマンドを通じてコードカバレッジを測定する機能が組み込まれています。これは、テスト実行中にコードのどの部分が実行されたかを追跡し、その割合を報告するものです。開発者はこの情報を用いて、テストがコードベースのどの程度をカバーしているかを把握し、テストの網羅性を向上させることができます。
go test -cover
: テストを実行し、カバレッジの概要(パーセンテージ)を出力します。go test -coverprofile=coverage.out
: 詳細なカバレッジプロファイルをファイルに保存します。go tool cover -html=coverage.out
: 保存されたカバレッジプロファイルから、ブラウザで閲覧可能なHTMLレポートを生成します。これにより、コードのどの行がカバーされているか、されていないかを視覚的に確認できます。
cgo
cgo
は、GoプログラムからC言語のコードを呼び出すためのGoの機能です。これにより、既存のCライブラリをGoプロジェクトで利用したり、パフォーマンスが重要な部分をCで記述したりすることが可能になります。cgo
を使用するGoファイルでは、特別なimport "C"
ステートメントと、Cコードを記述するためのコメントブロックを使用します。
cgo
の仕組みは、GoコンパイラがGoコードとCコードを連携させるための接着コードを生成することに基づいています。Goのビルドプロセス中に、cgo
はCコードをコンパイルし、Goコードから呼び出せるようにリンクします。
cgoにおけるコードカバレッジの課題
Goの標準的なコードカバレッジツールは、Go言語で書かれたコードの計測に特化しています。そのため、cgo
を介して呼び出されるC言語のコードについては、Goのカバレッジツールでは直接カバレッジを測定できません。Cコードのカバレッジを測定するには、gcov
のようなC言語向けの専用ツールを使用し、Cコードを適切なフラグ(例: GCCの-fprofile-arcs -ftest-coverage
)でコンパイルし、別途カバレッジデータを収集・分析する必要があります。
このコミットの文脈では、cgo
を使用しているGoパッケージ全体のカバレッジが、Goのツールによって正しく計算されるかどうかが焦点となっています。特に、cgo
の存在がGoコードのカバレッジ測定に悪影響を与えないことを確認することが重要です。
技術的詳細
このコミットは、go test -cover
コマンドがcgo
を含むGoパッケージに対して正しく機能するかを検証するための新しいテストケースを追加します。
-
テストスクリプトの変更 (
src/cmd/go/test.bash
):TEST coverage with cgo
という新しいテストセクションが追加されています。- 一時ディレクトリを作成し、その中で
./testgo test -short -cover ./testdata/cgocover
コマンドを実行します。これは、cgocover
というテストデータディレクトリ内のパッケージに対して、ショートモードでカバレッジ測定を行いながらテストを実行することを意味します。 - テストの出力は一時ファイルにリダイレクトされます。
grep 'coverage: 0.0%' $d/cgo.out
コマンドを使用して、出力に「coverage: 0.0%」という文字列が含まれていないかを確認します。もし含まれていれば、それはcgo
パッケージのカバレッジが正しく測定されていないことを意味し、テストは失敗します。これは、cgo
を含むパッケージでも0%ではないカバレッジが報告されることを期待しているためです。
-
テスト対象のGoパッケージ (
src/cmd/go/testdata/cgocover/p.go
):p
という名前の新しいGoパッケージが作成されています。- このパッケージには、
cgo
を使用してC言語の関数f
を呼び出すGo関数F()
が含まれています。 - C言語の関数
f
は、Goのコメントブロック内に定義されています。 - Go関数
F()
内には、b
というブール変数に基づいた条件分岐と無限ループ(for {}
)が含まれています。これは、カバレッジ測定の対象となるGoコードのパスを提供するためです。C.f()
の呼び出しも含まれており、cgo
の利用を示しています。
-
テストファイル (
src/cmd/go/testdata/cgocover/p_test.go
):p
パッケージのテストファイルが作成されています。TestF()
というテスト関数が定義されており、これは単にp.F()
関数を呼び出すだけです。これにより、p.F()
内のGoコードが実行され、カバレッジデータが収集されるようになります。
この一連の変更により、go test -cover
がcgo
を含むGoパッケージに対して、少なくとも0%ではないカバレッジを報告することを確認する自動テストが追加されました。これは、cgo
の存在がGoコードのカバレッジ測定を妨げないことを保証するための重要なステップです。
コアとなるコードの変更箇所
src/cmd/go/test.bash
--- a/src/cmd/go/test.bash
+++ b/src/cmd/go/test.bash
@@ -568,6 +568,16 @@ TEST coverage runs
./testgo test -short -coverpkg=strings strings regexp || ok=false
./testgo test -short -cover strings math regexp || ok=false
+TEST coverage with cgo
+d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
+./testgo test -short -cover ./testdata/cgocover >$d/cgo.out 2>&1 || ok=false
+cat $d/cgo.out
+if grep 'coverage: 0.0%' $d/cgo.out >/dev/null; then
+ ok=false
+ echo no coverage for cgo package
+ ok=false
+fi
+
TEST cgo depends on syscall
rm -rf $GOROOT/pkg/*_race
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
src/cmd/go/testdata/cgocover/p.go
--- /dev/null
+++ b/src/cmd/go/testdata/cgocover/p.go
@@ -0,0 +1,19 @@
+package p
+
+/*
+void
+f(void)
+{
+}
+*/
+import "C"
+
+var b bool
+
+func F() {
+ if b {
+ for {
+ }
+ }
+ C.f()
+}
src/cmd/go/testdata/cgocover/p_test.go
--- /dev/null
+++ b/src/cmd/go/testdata/cgocover/p_test.go
@@ -0,0 +1,7 @@
+package p
+
+import "testing"
+
+func TestF(t *testing.T) {
+ F()
+}
コアとなるコードの解説
src/cmd/go/test.bash
の変更
このシェルスクリプトの変更は、cgo
を含むGoパッケージのテストカバレッジを検証するための新しいテストブロックを追加しています。
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
: 一時ディレクトリを作成し、そのパスをd
変数に格納します。これはテストの実行中に生成されるファイル(この場合はcgo.out
)を格納するために使用されます。./testgo test -short -cover ./testdata/cgocover >$d/cgo.out 2>&1 || ok=false
:./testgo
: Goツールチェインのテスト実行バイナリです。test -short -cover
: テストをショートモードで実行し、コードカバレッジを有効にします。./testdata/cgocover
: テスト対象のパッケージが格納されているディレクトリを指定します。>$d/cgo.out 2>&1
: 標準出力と標準エラー出力を$d/cgo.out
ファイルにリダイレクトします。|| ok=false
: コマンドが失敗した場合(終了コードが0以外の場合)、ok
変数をfalse
に設定します。これは、テストスクリプト全体の成功/失敗を追跡するための一般的なパターンです。
cat $d/cgo.out
: 生成されたカバレッジレポートの内容を標準出力に表示します。これはデバッグ目的で役立ちます。if grep 'coverage: 0.0%' $d/cgo.out >/dev/null; then ... fi
:grep 'coverage: 0.0%' $d/cgo.out
:cgo.out
ファイル内に「coverage: 0.0%」という文字列が含まれているかを検索します。>/dev/null
:grep
の出力を破棄します。grep
の終了コードのみを利用します(マッチすれば0、しなければ1)。ok=false; echo no coverage for cgo package; ok=false
: もし「coverage: 0.0%」が見つかった場合、ok
をfalse
に設定し、エラーメッセージを出力します。これは、cgo
を含むパッケージでもカバレッジが0%ではないことを期待しているためです。
このスクリプトは、cgo
パッケージのカバレッジが正しく測定され、0%ではない値が報告されることを保証するための基本的な健全性チェックとして機能します。
src/cmd/go/testdata/cgocover/p.go
の新規追加
このファイルは、cgo
を使用するGoパッケージの最小限の例です。
package p
:p
という名前のパッケージを定義します。/* ... */ import "C"
:cgo
の構文です。このコメントブロック内にC言語のコードを記述し、import "C"
によってGoコードからそのCコードを呼び出せるようになります。ここでは、引数も戻り値もないシンプルなC関数f()
が定義されています。var b bool
: カバレッジ測定の対象となるGoコードのパスを作成するために使用されるブール変数です。func F() { ... }
:if b { for {} }
: この条件分岐は、カバレッジツールがGoコードの実行パスを追跡できることを確認するために含まれています。b
がtrue
の場合、無限ループに入ります。実際のテストではb
はfalse
であるため、このブロックは実行されず、カバレッジレポートで未カバーとしてマークされる可能性があります。C.f()
:cgo
を介してC言語の関数f()
を呼び出します。これが、このパッケージがcgo
を使用していることを示す主要な部分です。
このファイルは、cgo
とGoコードが混在する状況で、GoのカバレッジツールがGoコード部分を正しく計測できるかどうかのテスト対象となります。
src/cmd/go/testdata/cgocover/p_test.go
の新規追加
このファイルは、p.go
パッケージのテストファイルです。
package p
:p
パッケージのテストであることを示します。import "testing"
: Goの標準テストパッケージをインポートします。func TestF(t *testing.T) { F() }
:TestF
:testing
パッケージの規約に従ったテスト関数です。F()
: テスト対象のp.F()
関数を呼び出します。この呼び出しにより、p.F()
内のGoコードが実行され、カバレッジデータが収集されます。
このシンプルなテストは、p.F()
関数が実行されることを保証し、その結果としてp.go
内のGoコード(if b { ... }
とC.f()
の呼び出しを含む)のカバレッジが測定されるようにします。
関連リンク
- Go CL 71230049: https://golang.org/cl/71230049
参考にした情報源リンク
- Go言語のコードカバレッジに関する情報:
- https://medium.com/@siddharth_goel/go-code-coverage-a-comprehensive-guide-2023-b9e2e2e2e2e2
- https://medium.com/@siddharth_goel/go-code-coverage-a-comprehensive-guide-2023-b9e2e2e2e2e2 (重複していますが、検索結果で複数回出てきたため記載)
- https://stackoverflow.com/questions/22000000/how-to-get-code-coverage-for-go-programs
- https://go.dev/blog/cover
cgo
におけるCコードカバレッジの課題に関する情報:- https://github.com/golang/go/issues/10859 (直接のIssue #6333ではないが、
cgo
とカバレッジに関する関連情報として)
- https://github.com/golang/go/issues/10859 (直接のIssue #6333ではないが、