[インデックス 17991] ファイルの概要
コミット
このコミットは、Go言語のunicode/utf16
パッケージ内のIsSurrogate
関数に対して、明示的なテストケースを追加するものです。これにより、IsSurrogate
関数の正確性が保証され、UTF-16サロゲートペアの処理に関する堅牢性が向上します。
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/fb31a0b1d010da48e53cce16e16c36aed58ab6cb
元コミット内容
commit fb31a0b1d010da48e53cce16e16c36aed58ab6cb
Author: Dave Cheney <dave@cheney.net>
Date: Mon Dec 16 11:15:23 2013 +1100
unicode/utf16: add explicit tests for IsSurrogate
Update #6956
Add tests for IsSurrogate.
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/42570043
---
src/pkg/unicode/utf16/utf16_test.go | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/src/pkg/unicode/utf16/utf16_test.go b/src/pkg/unicode/utf16/utf16_test.go
index ee16a303df..05d6427b05 100644
--- a/src/pkg/unicode/utf16/utf16_test.go
+++ b/src/pkg/unicode/utf16/utf16_test.go
@@ -99,3 +99,31 @@ func TestDecode(t *testing.T) {
}\n \t}\n }\n+\n+var surrogateTests = []struct {\n+\tr rune\n+\twant bool\n+}{\n+\t// from http://en.wikipedia.org/wiki/UTF-16\n+\t{'\\u007A', false}, // LATIN SMALL LETTER Z\n+\t{'\\u6C34', false}, // CJK UNIFIED IDEOGRAPH-6C34 (water)\n+\t{'\\uFEFF', false}, false}, // Byte Order Mark\n+\t{'\\U00010000', false}, // LINEAR B SYLLABLE B008 A (first non-BMP code point)\n+\t{'\\U0001D11E', false}, // MUSICAL SYMBOL G CLEF\n+\t{'\\U0010FFFD', false}, // PRIVATE USE CHARACTER-10FFFD (last Unicode code point)\n+\n+\t{rune(0xd7ff), false}, // surr1-1\n+\t{rune(0xd800), true}, // surr1\n+\t{rune(0xdc00), true}, // surr2\n+\t{rune(0xe000), false}, // surr3\n+\t{rune(0xdfff), true}, // surr3-1\n+}\n+\n+func TestIsSurrogate(t *testing.T) {\n+\tfor i, tt := range surrogateTests {\n+\t\tgot := IsSurrogate(tt.r)\n+\t\tif got != tt.want {\n+\t\t\tt.Errorf("%d: IsSurrogate(%q) = %v; want %v", i, tt.r, got, tt.want)\n+\t\t}\n+\t}\n+}\n```
## 変更の背景
このコミットの背景には、Go言語の`unicode/utf16`パッケージにおける`IsSurrogate`関数のテストカバレッジを向上させるという目的があります。元のコードにはこの関数に対する明示的なテストが存在せず、その正確性を保証するためのテストケースが不足していました。
Unicodeの文字集合は非常に広範であり、特に基本多言語面(BMP: Basic Multilingual Plane, U+0000からU+FFFFまで)を超える文字(サロゲートペアで表現される文字)の扱いは複雑です。`IsSurrogate`関数は、与えられたUnicodeコードポイントがUTF-16のサロゲート範囲内にあるかどうかを判定する重要な役割を担っています。この関数の正確な動作は、UTF-16エンコーディングのデコードやエンコード処理において不可欠です。
コミットメッセージに記載されている`Update #6956`は、このテスト追加がGoのIssue 6956に関連していることを示唆しています。具体的なIssueの内容は不明ですが、おそらく`IsSurrogate`関数の動作に関する問題報告や、テストの不足が指摘されたものと推測されます。
## 前提知識の解説
### Unicodeと文字エンコーディング
* **Unicode**: 世界中のほとんどの文字を統一的に扱うための文字コード標準です。各文字には一意の「コードポイント」(数値)が割り当てられています。
* **UTF-8, UTF-16, UTF-32**: Unicodeのコードポイントをコンピュータ上で表現するためのエンコーディング方式です。
* **UTF-8**: 可変長エンコーディングで、ASCII文字は1バイト、それ以外の文字は2〜4バイトで表現されます。Webで広く使われています。
* **UTF-16**: 可変長エンコーディングで、基本的には16ビット(2バイト)単位で文字を表現します。BMP内の文字は16ビットで表現されますが、BMP外の文字は「サロゲートペア」と呼ばれる2つの16ビット単位で表現されます。
* **UTF-32**: 固定長エンコーディングで、すべての文字を32ビット(4バイト)で表現します。
### UTF-16とサロゲートペア
UTF-16は、Unicodeのコードポイントを16ビットのコードユニットのシーケンスとしてエンコードします。
* **基本多言語面 (BMP)**: U+0000からU+FFFFまでの範囲のコードポイントを指します。この範囲の文字は、1つの16ビットコードユニットで直接表現されます。
* **サロゲートペア**: BMP外の文字(U+10000からU+10FFFFまでの範囲のコードポイント)を表現するために使用される特殊なメカニズムです。これらの文字は、2つの16ビットコードユニットのペアで表現されます。
* **上位サロゲート (High Surrogate)**: U+D800からU+DBFFまでの範囲のコードポイント。
* **下位サロゲート (Low Surrogate)**: U+DC00からU+DFFFまでの範囲のコードポイント。
これらの範囲は、Unicodeによってサロゲート専用に予約されており、通常の文字には割り当てられていません。これにより、単一のサロゲートコードユニットが有効な文字と誤認されることを防ぎます。上位サロゲートの後に下位サロゲートが続くことで、1つのBMP外の文字が表現されます。
### Go言語の`rune`型
Go言語では、Unicodeのコードポイントは`rune`型(`int32`のエイリアス)で表現されます。これは、単一のUnicode文字を表すために使用されます。`IsSurrogate`関数は、この`rune`型の値がサロゲート範囲内にあるかどうかを判定します。
## 技術的詳細
`unicode/utf16`パッケージは、UTF-16エンコーディングとデコーディングに関連する機能を提供します。このコミットでテストが追加された`IsSurrogate`関数は、Go言語の`rune`型(`int32`)を受け取り、その値がUTF-16のサロゲート範囲(U+D800からU+DFFF)に属するかどうかを真偽値で返します。
具体的には、`IsSurrogate(r rune) bool`関数は、以下の条件が真である場合に`true`を返します。
* `r`が上位サロゲートの範囲(U+D800からU+DBFF)にある場合
* `r`が下位サロゲートの範囲(U+DC00からU+DFFF)にある場合
この関数は、UTF-16のエンコード/デコード処理において、入力されたコードポイントがサロゲートペアの一部であるかどうかを効率的に判断するために利用されます。例えば、UTF-16のデコード処理では、上位サロゲートが検出された場合、次に下位サロゲートが続くことを期待し、両者を組み合わせてBMP外の文字を再構築します。`IsSurrogate`関数は、このようなロジックの健全性を保証するために不可欠です。
追加されたテストケース`surrogateTests`は、`IsSurrogate`関数の様々な入力に対する期待される出力を網羅しています。これには、通常のBMP文字、BMP外の文字(ただし、`IsSurrogate`は個々のサロゲートコードポイントを判定するため、これらの文字自体は`false`となる)、そしてサロゲート範囲の境界値やその近傍のコードポイントが含まれています。これにより、関数のロジックが正しく、エッジケースも適切に処理されることが確認されます。
## コアとなるコードの変更箇所
このコミットによる変更は、`src/pkg/unicode/utf16/utf16_test.go`ファイルにのみ行われています。具体的には、以下のテストコードが追加されました。
1. `surrogateTests`という名前の構造体スライスが定義されています。このスライスは、テスト対象の`rune`値と、それに対する`IsSurrogate`関数の期待される結果(`true`または`false`)のペアを保持しています。
* 通常の文字(`'\\u007A'`, `'\\u6C34'`, `'\\uFEFF'`)や、BMP外の文字(`'\\U00010000'`, `'\\U0001D11E'`, `'\\U0010FFFD'`)に対しては`false`が期待されます。これは、これらの文字自体はサロゲートコードポイントではないためです。
* サロゲート範囲の境界値やその近傍のコードポイント(`0xd7ff`, `0xd800`, `0xdc00`, `0xe000`, `0xdfff`)に対しては、期待される`true`/`false`が設定されています。特に`0xd800`(上位サロゲートの開始)と`0xdc00`(下位サロゲートの開始)、`0xdfff`(下位サロゲートの終了)は`true`が期待されます。
2. `TestIsSurrogate`というテスト関数が追加されています。この関数は`surrogateTests`スライスをイテレートし、各テストケースに対して`IsSurrogate`関数を呼び出し、その結果が期待される値と一致するかどうかを検証します。もし一致しない場合は、`t.Errorf`を使ってエラーを報告します。
## コアとなるコードの解説
追加されたテストコードは、`IsSurrogate`関数の動作を網羅的に検証することを目的としています。
`surrogateTests`スライスは、テストの入力と期待される出力を明確に定義しています。
* `'\\u007A'` (LATIN SMALL LETTER Z), `'\\u6C34'` (CJK UNIFIED IDEOGRAPH-6C34), `'\\uFEFF'` (Byte Order Mark) は、いずれもBMP内の通常の文字であり、サロゲート範囲外であるため、`IsSurrogate`は`false`を返すことが期待されます。
* `'\\U00010000'` (LINEAR B SYLLABLE B008 A), `'\\U0001D11E'` (MUSICAL SYMBOL G CLEF), `'\\U0010FFFD'` (PRIVATE USE CHARACTER-10FFFD) は、BMP外の文字です。これらの文字はUTF-16ではサロゲートペアとして表現されますが、`IsSurrogate`関数は個々の`rune`がサロゲートコードポイントであるかを判定するため、これらの文字自体(完全なコードポイント)に対しては`false`を返すことが期待されます。
* `rune(0xd7ff)`: サロゲート範囲の直前のコードポイント。`false`が期待されます。
* `rune(0xd800)`: 上位サロゲートの開始コードポイント。`true`が期待されます。
* `rune(0xdc00)`: 下位サロゲートの開始コードポイント。`true`が期待されます。
* `rune(0xe000)`: サロゲート範囲の直後のコードポイント。`false`が期待されます。
* `rune(0xdfff)`: 下位サロゲートの終了コードポイント。`true`が期待されます。
`TestIsSurrogate`関数は、これらのテストケースをループで実行し、`IsSurrogate`関数の実際の出力と期待される出力を比較します。これにより、`IsSurrogate`関数がUnicodeのサロゲート範囲の定義に厳密に従って動作していることが保証されます。特に、境界値のテストは、オフバイワンエラーなどの潜在的なバグを発見するために非常に重要です。
このテストの追加により、将来的に`IsSurrogate`関数の実装が変更された場合でも、既存の動作が維持されることが保証され、リグレッションを防ぐことができます。
## 関連リンク
* Go言語の`unicode/utf16`パッケージのドキュメント: [https://pkg.go.dev/unicode/utf16](https://pkg.go.dev/unicode/utf16)
* Go言語の`rune`型に関するドキュメント: [https://go.dev/blog/strings](https://go.dev/blog/strings)
## 参考にした情報源リンク
* UTF-16 - Wikipedia: [https://ja.wikipedia.org/wiki/UTF-16](https://ja.wikipedia.org/wiki/UTF-16)
* Surrogates - Unicode Glossary: [https://www.unicode.org/glossary/s.htm#Surrogates](https://www.unicode.org/glossary/s.htm#Surrogates)
* Go言語の`unicode/utf16.IsSurrogate`関数の説明 (Web検索結果より): [https://pkg.go.dev/unicode/utf16#IsSurrogate](https://pkg.go.dev/unicode/utf16#IsSurrogate) (これはGoの公式ドキュメントへのリンクです)
* UTF-16 surrogate pairs (Web検索結果より): [https://en.wikipedia.org/wiki/UTF-16#Surrogates](https://en.wikipedia.org/wiki/UTF-16#Surrogates) (これはWikipediaのUTF-16のサロゲートに関するセクションへのリンクです)